Skip to content

Commit 6afe999

Browse files
authored
Fix for extended_arg NOPs (#117)
* Fix rare extended_arg NOPs not being processable by concrete._remove_extended_args Signed-off-by: EmmaJaneBonestell <EmmaJaneBonestell@gmail.com> * Properly version types.CodeType arguments for test_extended_arg_nop Signed-off-by: EmmaJaneBonestell <EmmaJaneBonestell@gmail.com> --------- Signed-off-by: EmmaJaneBonestell <EmmaJaneBonestell@gmail.com>
1 parent 75948ed commit 6afe999

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

src/bytecode/concrete.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ def _remove_extended_args(
739739
continue
740740

741741
if extended_arg is not None:
742-
arg = (extended_arg << 8) + instr.arg
742+
arg = UNSET if instr.name == "NOP" else (extended_arg << 8) + instr.arg
743743
extended_arg = None
744744

745745
instr = ConcreteInstr(

tests/test_concrete.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,55 @@ def foo(x: int, y: int):
785785
self.assertEqual(concrete.consts, consts)
786786
self.assertInstructionListEqual(list(concrete), expected)
787787

788+
# Ensure that concrete._remove_extended_args can handle extended_arg NOPs that get
789+
# passed in from other to_code/from_code methods.
790+
def test_extended_arg_nop(self):
791+
constants = [None] * (0x000129 + 1)
792+
constants[0x000129] = "Arbitrary String"
793+
# EXTENDED_ARG 0x01, NOP 0xFF, EXTENDED_ARG 0x01,
794+
# LOAD_CONST 0x29, RETURN_VALUE 0x00
795+
codestring = bytes([0x90, 0x01, 0x09, 0xFF, 0x90, 0x01, 0x64, 0x29, 0x53, 0x00])
796+
codetype_list = [
797+
0,
798+
0,
799+
0,
800+
1,
801+
64,
802+
codestring,
803+
tuple(constants),
804+
(),
805+
(),
806+
"<no file>",
807+
"code",
808+
1,
809+
b"",
810+
(),
811+
(),
812+
]
813+
if sys.version_info >= (3, 8):
814+
codetype_list.insert(1, 0)
815+
if sys.version_info >= (3, 11):
816+
codetype_list.insert(12, "code")
817+
codetype_list.insert(14, bytes())
818+
codetype_args = tuple(codetype_list)
819+
code = types.CodeType(*codetype_args)
820+
# Check it can be encoded and decoded
821+
codetype_output = Bytecode.from_code(code).to_code().co_consts
822+
823+
code = ConcreteBytecode()
824+
code.consts = constants
825+
code.extend(
826+
[
827+
ConcreteInstr("EXTENDED_ARG", 0x01),
828+
ConcreteInstr("NOP"),
829+
ConcreteInstr("EXTENDED_ARG", 0x01),
830+
ConcreteInstr("LOAD_CONST", 0x29),
831+
ConcreteInstr("RETURN_VALUE"),
832+
]
833+
)
834+
concrete_output = ConcreteBytecode.to_code(code).co_consts
835+
self.assertEqual(codetype_output, concrete_output)
836+
788837
# The next three tests ensure we can round trip ConcreteBytecode generated
789838
# with extended_args=True
790839

0 commit comments

Comments
 (0)