Beispiel #1
0
    def test_extended_arg(self):
        # Create a code object from arbitrary bytecode
        co_code = (b'\x90\x12\x904\x90\xabd\xcd'
                   if WORDCODE else b'\x904\x12d\xcd\xab')
        code = get_code('x=1')
        code = types.CodeType(code.co_argcount, code.co_kwonlyargcount,
                              code.co_nlocals, code.co_stacksize,
                              code.co_flags, co_code, code.co_consts,
                              code.co_names, code.co_varnames,
                              code.co_filename, code.co_name,
                              code.co_firstlineno, code.co_lnotab,
                              code.co_freevars, code.co_cellvars)

        # without EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code)
        self.assertListEqual(
            list(bytecode),
            [ConcreteInstr("LOAD_CONST", 0x1234abcd, lineno=1)])

        # with EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code, extended_arg=True)
        if WORDCODE:
            expected = [
                ConcreteInstr('EXTENDED_ARG', 0x12, lineno=1),
                ConcreteInstr('EXTENDED_ARG', 0x34, lineno=1),
                ConcreteInstr('EXTENDED_ARG', 0xab, lineno=1),
                ConcreteInstr('LOAD_CONST', 0xcd, lineno=1)
            ]
        else:
            expected = [
                ConcreteInstr('EXTENDED_ARG', 0x1234, lineno=1),
                ConcreteInstr('LOAD_CONST', 0xabcd, lineno=1)
            ]
        self.assertListEqual(list(bytecode), expected)
Beispiel #2
0
    def test_extended_arg(self):
        # Create a code object from arbitrary bytecode
        co_code = b'\x904\x12d\xcd\xab'
        code = get_code('x=1')
        code = types.CodeType(code.co_argcount,
                              code.co_kwonlyargcount,
                              code.co_nlocals,
                              code.co_stacksize,
                              code.co_flags,
                              co_code,
                              code.co_consts,
                              code.co_names,
                              code.co_varnames,
                              code.co_filename,
                              code.co_name,
                              code.co_firstlineno,
                              code.co_lnotab,
                              code.co_freevars,
                              code.co_cellvars)

        # without EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code)
        self.assertListEqual(list(bytecode),
                             [ConcreteInstr("LOAD_CONST", 0x1234abcd, lineno=1)])

        # with EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code, extended_arg=True)
        self.assertListEqual(list(bytecode),
                             [ConcreteInstr('EXTENDED_ARG', 0x1234, lineno=1),
                              ConcreteInstr('LOAD_CONST', 0xabcd, lineno=1)])
Beispiel #3
0
    def test_extended_arg_make_function(self):
        code_obj = get_code('''
            def foo(x: int, y: int):
                pass
        ''')

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if WORDCODE:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        else:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 3 << 16, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if not WORDCODE:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("EXTENDED_ARG", 3, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 0, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        self.assertListEqual(list(concrete), expected)
Beispiel #4
0
    def test_extended_arg_make_function(self):
        code_obj = get_code('''
            def foo(x: int, y: int):
                pass
        ''')

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if WORDCODE:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        else:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 3 << 16, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if not WORDCODE:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("EXTENDED_ARG", 3, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 0, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        self.assertListEqual(list(concrete), expected)
Beispiel #5
0
    def make_bytecode(self, symbol_table):
        code = [
            Instr("LOAD_CONST", symbol_table["write_func"]),
            Instr("LOAD_NAME", "_output"),
            Instr("LOAD_NAME", "str")
        ]

        compiled_expr = compile(self.variable_name,
                                filename="<none>",
                                mode="eval")
        concrete_bytecode = ConcreteBytecode.from_code(compiled_expr)
        inner = concrete_bytecode.to_bytecode()

        # The compiler drops a return statement at the end of the
        # expression, which we want to strip off so that we can use
        # the result
        inner.pop()

        code += inner

        code += [
            Instr("CALL_FUNCTION", 1),
            Instr("CALL_FUNCTION", 2),
            Instr("POP_TOP")
        ]

        return code
Beispiel #6
0
    def test_cellvar_freevar(self):
        concrete = ConcreteBytecode()
        concrete.cellvars = ["cell"]
        concrete.freevars = ["free"]
        concrete.append(ConcreteInstr("LOAD_DEREF", 0))
        concrete.append(ConcreteInstr("LOAD_DEREF", 1))
        code = concrete.to_code()

        concrete = ConcreteBytecode.from_code(code)
        self.assertEqual(concrete.cellvars, ["cell"])
        self.assertEqual(concrete.freevars, ["free"])
        self.assertEqual(
            list(concrete),
            [
                ConcreteInstr("LOAD_DEREF", 0, lineno=1),
                ConcreteInstr("LOAD_DEREF", 1, lineno=1),
            ],
        )

        bytecode = concrete.to_bytecode()
        self.assertEqual(bytecode.cellvars, ["cell"])
        self.assertEqual(
            list(bytecode),
            [
                Instr("LOAD_DEREF", CellVar("cell"), lineno=1),
                Instr("LOAD_DEREF", FreeVar("free"), lineno=1),
            ],
        )
Beispiel #7
0
    def instrument_code_recursive(
            self,
            code: CodeType,
            parent_code_object_id: Optional[int] = None) -> CodeType:
        """Instrument the given Code Object recursively.

        :param code: The code object to be instrumented.
        :param parent_code_object_id: Internal id of the code object to which this code object belongs
        (can be None if `code` is the highest node, i.e. the module node).
        :return The instrumented code object.
        """
        # The original bytecode should match the disassembly, so EXTENDED_ARG is included
        # original_cfg = CFG.from_bytecode(ConcreteBytecode.from_code(code, extended_arg=False).to_bytecode())
        original_cfg = CFG.from_bytecode(
            ConcreteBytecode.from_code(code, extended_arg=False).to_bytecode())
        original_cdg = ControlDependenceGraph.compute(original_cfg)
        cfg = CFG.from_bytecode(Bytecode.from_code(code))
        code_object_id = self._tracer.register_code_object(
            CodeObjectMetaData(code.co_filename, code, parent_code_object_id,
                               original_cfg, cfg, original_cdg))
        assert cfg.entry_node is not None, "Entry node cannot be None."

        module_entry = False
        if not parent_code_object_id:
            # This is the module entry, in which we want to import the ExecutionTracer
            self._instrument_import(cfg)
            module_entry = True

        self._instrument_cfg(cfg, original_cfg, code_object_id, module_entry)
        return self._instrument_inner_code_objects(
            cfg.bytecode_cfg().to_code(), code_object_id)
Beispiel #8
0
    def test_extended_arg(self):
        # Create a code object from arbitrary bytecode
        co_code = b"\x90\x12\x904\x90\xabd\xcd" if WORDCODE else b"\x904\x12d\xcd\xab"
        code = get_code("x=1")
        args = ((code.co_argcount, ) if sys.version_info < (3, 8) else
                (code.co_argcount, code.co_posonlyargcount))
        args += (
            code.co_kwonlyargcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            code.co_filename,
            code.co_name,
            code.co_firstlineno,
            code.co_lnotab,
            code.co_freevars,
            code.co_cellvars,
        )

        code = types.CodeType(*args)

        # without EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code)
        self.assertListEqual(
            list(bytecode),
            [ConcreteInstr("LOAD_CONST", 0x1234ABCD, lineno=1)])

        # with EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code, extended_arg=True)
        if WORDCODE:
            expected = [
                ConcreteInstr("EXTENDED_ARG", 0x12, lineno=1),
                ConcreteInstr("EXTENDED_ARG", 0x34, lineno=1),
                ConcreteInstr("EXTENDED_ARG", 0xAB, lineno=1),
                ConcreteInstr("LOAD_CONST", 0xCD, lineno=1),
            ]
        else:
            expected = [
                ConcreteInstr("EXTENDED_ARG", 0x1234, lineno=1),
                ConcreteInstr("LOAD_CONST", 0xABCD, lineno=1),
            ]
        self.assertListEqual(list(bytecode), expected)
Beispiel #9
0
    def test_packing_lines(self):
        from bytecode.tests.long_lines_example import long_lines
        import dis

        line_starts = list(dis.findlinestarts(long_lines.__code__))

        concrete = ConcreteBytecode.from_code(long_lines.__code__)
        as_code = concrete.to_code()
        self.assertEqual(line_starts, list(dis.findlinestarts(as_code)))
Beispiel #10
0
    def test_extended_arg_unpack_ex(self):
        def test():
            p = [1, 2, 3, 4, 5, 6]
            q, r, *s, t = p
            return q, r, s, t

        test.__code__ = ConcreteBytecode.from_code(test.__code__, extended_arg=True).to_code()
        self.assertEqual(test.__code__.co_stacksize, 6)
        self.assertEqual(test(), (1, 2, [3, 4, 5], 6))
Beispiel #11
0
 def test_attr(self):
     code_obj = get_code("x = 5")
     code = ConcreteBytecode.from_code(code_obj)
     self.assertEqual(code.consts, [5, None])
     self.assertEqual(code.names, ['x'])
     self.assertEqual(code.varnames, [])
     self.assertEqual(code.freevars, [])
     self.assertListEqual(list(code),
                          [ConcreteInstr('LOAD_CONST', 0, lineno=1),
                           ConcreteInstr('STORE_NAME', 0, lineno=1),
                           ConcreteInstr('LOAD_CONST', 1, lineno=1),
                           ConcreteInstr('RETURN_VALUE', lineno=1)])
Beispiel #12
0
 def test_attr(self):
     code_obj = get_code("x = 5")
     code = ConcreteBytecode.from_code(code_obj)
     self.assertEqual(code.consts, [5, None])
     self.assertEqual(code.names, ['x'])
     self.assertEqual(code.varnames, [])
     self.assertEqual(code.freevars, [])
     self.assertListEqual(list(code),
                          [ConcreteInstr('LOAD_CONST', 0, lineno=1),
                           ConcreteInstr('STORE_NAME', 0, lineno=1),
                           ConcreteInstr('LOAD_CONST', 1, lineno=1),
                           ConcreteInstr('RETURN_VALUE', lineno=1)])
Beispiel #13
0
    def check(self, source, function=False):
        ref_code = get_code(source, function=function)

        code = ConcreteBytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        code = Bytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        bytecode = Bytecode.from_code(ref_code)
        blocks = ControlFlowGraph.from_bytecode(bytecode)
        code = blocks.to_bytecode().to_code()
        self.assertEqual(code, ref_code)
Beispiel #14
0
    def check(self, source, function=False):
        ref_code = get_code(source, function=function)

        code = ConcreteBytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        code = Bytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        bytecode = Bytecode.from_code(ref_code)
        blocks = ControlFlowGraph.from_bytecode(bytecode)
        code = blocks.to_bytecode().to_code()
        self.assertEqual(code, ref_code)
Beispiel #15
0
    def test_freevar(self):
        concrete = ConcreteBytecode()
        concrete.freevars = ["x"]
        concrete.append(ConcreteInstr("LOAD_DEREF", 0))
        code = concrete.to_code()

        concrete = ConcreteBytecode.from_code(code)
        self.assertEqual(concrete.cellvars, [])
        self.assertEqual(concrete.freevars, ["x"])
        self.assertEqual(list(concrete), [ConcreteInstr("LOAD_DEREF", 0, lineno=1)])

        bytecode = concrete.to_bytecode()
        self.assertEqual(bytecode.cellvars, [])
        self.assertEqual(list(bytecode), [Instr("LOAD_DEREF", FreeVar("x"), lineno=1)])
    def test_extended_arg(self):
        # Create a code object from arbitrary bytecode
        co_code = b"%c4\x12d\xcd\xab" % EXTENDED_ARG
        code = get_code("x=1")
        args = (
            code.co_argcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            code.co_filename,
            code.co_name,
            code.co_firstlineno,
            code.co_lnotab,
            code.co_freevars,
            code.co_cellvars,
        )

        code = types.CodeType(*args)

        # without EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code)
        self.assertListEqual(
            list(bytecode),
            [ConcreteInstr("LOAD_CONST", 0x1234ABCD, lineno=1)])

        # with EXTENDED_ARG opcode
        bytecode = ConcreteBytecode.from_code(code, extended_arg=True)
        expected = [
            ConcreteInstr("EXTENDED_ARG", 0x1234, lineno=1),
            ConcreteInstr("LOAD_CONST", 0xABCD, lineno=1),
        ]
        self.assertListEqual(list(bytecode), expected)
Beispiel #17
0
 def test_attr(self):
     code_obj = get_code("x = 5")
     code = ConcreteBytecode.from_code(code_obj)
     self.assertEqual(code.consts, [5, None])
     self.assertEqual(code.names, ["x"])
     self.assertEqual(code.varnames, [])
     self.assertEqual(code.freevars, [])
     self.assertListEqual(
         list(code),
         [
             ConcreteInstr("LOAD_CONST", 0, lineno=1),
             ConcreteInstr("STORE_NAME", 0, lineno=1),
             ConcreteInstr("LOAD_CONST", 1, lineno=1),
             ConcreteInstr("RETURN_VALUE", lineno=1),
         ],
     )
Beispiel #18
0
    def test_cellvar(self):
        concrete = ConcreteBytecode()
        concrete.cellvars = ['x']
        concrete.append(ConcreteInstr('LOAD_DEREF', 0))
        code = concrete.to_code()

        concrete = ConcreteBytecode.from_code(code)
        self.assertEqual(concrete.cellvars, ['x'])
        self.assertEqual(concrete.freevars, [])
        self.assertEqual(list(concrete),
                         [ConcreteInstr('LOAD_DEREF', 0, lineno=1)])

        bytecode = concrete.to_bytecode()
        self.assertEqual(bytecode.cellvars, ['x'])
        self.assertEqual(list(bytecode),
                         [Instr('LOAD_DEREF', CellVar('x'), lineno=1)])
Beispiel #19
0
    def test_freevar(self):
        concrete = ConcreteBytecode()
        concrete.freevars = ['x']
        concrete.append(ConcreteInstr('LOAD_DEREF', 0))
        code = concrete.to_code()

        concrete = ConcreteBytecode.from_code(code)
        self.assertEqual(concrete.cellvars, [])
        self.assertEqual(concrete.freevars, ['x'])
        self.assertEqual(list(concrete),
                         [ConcreteInstr('LOAD_DEREF', 0, lineno=1)])

        bytecode = concrete.to_bytecode()
        self.assertEqual(bytecode.cellvars, [])
        self.assertEqual(list(bytecode),
                         [Instr('LOAD_DEREF', FreeVar('x'), lineno=1)])
Beispiel #20
0
def extract_code(frame, start=None, end=None, name="<withhack>"):
    """Extract a Code object corresponding to the given frame.

    Given a frame object, this function returns a byteplay Code object with
    containing the code being executed by the frame.  If the optional "start"
    "start" and/or "end" arguments are given, they are used as indices to
    return only a slice of the code.
    """
    code = frame.f_code

    if start is None:
        start = 0
    if end is None:
        end = len(code.co_code)

    # convert the byte indices into ConcreteBytecode indices
    start_c = 0
    end_c = 0
    at = 0
    concrete_bc = ConcreteBytecode.from_code(code)
    for c in concrete_bc:
        at += c.size
        if at < start:
            start_c += 1
        if at < end:
            end_c += 1

    # convert the ConcreteBytecode indices into Bytecode indices
    # assumes that instructions map one-to-one
    bc = concrete_bc.to_bytecode()
    start_b = None
    end_b = None
    at = 0
    for i, b in enumerate(bc):
        if at == start_c:
            start_b = i
        if at == end_c:
            end_b = i
        if isinstance(b, bytecode.instr.Instr):
            at += 1
    assert at == len(concrete_bc)

    bc[:] = bc[start_b:end_b]
    return bc
Beispiel #21
0
    def test_explicit_stacksize(self):
        # Passing stacksize=... to ConcreteBytecode.to_code should result in a
        # code object with the specified stacksize.  We pass some silly values
        # and assert that they are honored.
        code_obj = get_code("print('%s' % (a,b,c))")
        original_stacksize = code_obj.co_stacksize
        concrete = ConcreteBytecode.from_code(code_obj)

        # First with something bigger than necessary.
        explicit_stacksize = original_stacksize + 42
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)

        # Then with something bogus.  We probably don't want to advertise this
        # in the documentation.  If this fails then decide if it's for good
        # reason, and remove if so.
        explicit_stacksize = 0
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)
Beispiel #22
0
    def test_explicit_stacksize(self):
        # Passing stacksize=... to ConcreteBytecode.to_code should result in a
        # code object with the specified stacksize.  We pass some silly values
        # and assert that they are honored.
        code_obj = get_code("print('%s' % (a,b,c))")
        original_stacksize = code_obj.co_stacksize
        concrete = ConcreteBytecode.from_code(code_obj)

        # First with something bigger than necessary.
        explicit_stacksize = original_stacksize + 42
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)

        # Then with something bogus.  We probably don't want to advertise this
        # in the documentation.  If this fails then decide if it's for good
        # reason, and remove if so.
        explicit_stacksize = 0
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)
Beispiel #23
0
    def make_bytecode(self, symbol_table):
        label_end = Label()

        compiled_expr = compile(self.condition, filename="<none>", mode="eval")
        concrete_bytecode = ConcreteBytecode.from_code(compiled_expr)
        inner = concrete_bytecode.to_bytecode()

        # The compiler drops a return statement at the end of the
        # expression, which we want to strip off so that we can use
        # the result
        inner.pop()

        inner += [Instr("POP_JUMP_IF_FALSE", label_end)]

        for element in self.sequence.elements:
            inner += element.make_bytecode(symbol_table)

        inner += [label_end]

        return inner
Beispiel #24
0
    def test_extended_arg_make_function(self):
        if (3, 9) <= sys.version_info < (3, 10):
            from bytecode.tests.util_annotation import get_code as get_code_future

            code_obj = get_code_future(
                """
                def foo(x: int, y: int):
                    pass
                """
            )
        else:
            code_obj = get_code(
                """
                def foo(x: int, y: int):
                    pass
                """
            )

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        # With future annotation the int annotation is stringified and
        # stored as constant this the default behavior under Python 3.10
        if sys.version_info >= (3, 10):
            func_code = concrete.consts[3]
            names = ["foo"]
            consts = ["x", "int", "y", func_code, "foo", None, ("x", "int", "y", "int")]
            const_offset = 2
            first_instrs = [
                ConcreteInstr("LOAD_CONST", 6, lineno=1),
            ]
        elif (
            sys.version_info >= (3, 7)
            and concrete.flags & CompilerFlags.FUTURE_ANNOTATIONS
        ):
            func_code = concrete.consts[2]
            names = ["foo"]
            consts = ["int", ("x", "y"), func_code, "foo", None]
            const_offset = 1
            first_instrs = [
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0 + const_offset, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
            ]
        else:
            func_code = concrete.consts[1]
            names = ["int", "foo"]
            consts = [("x", "y"), func_code, "foo", None]
            const_offset = 0
            first_instrs = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0 + const_offset, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
            ]

        self.assertEqual(concrete.names, names)
        self.assertEqual(concrete.consts, consts)
        expected = first_instrs + [
            ConcreteInstr("LOAD_CONST", 1 + const_offset, lineno=1),
            ConcreteInstr("LOAD_CONST", 2 + const_offset, lineno=1),
            ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
            ConcreteInstr("STORE_NAME", 1 - bool(const_offset), lineno=1),
            ConcreteInstr("LOAD_CONST", 3 + const_offset, lineno=1),
            ConcreteInstr("RETURN_VALUE", lineno=1),
        ]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        # With future annotation the int annotation is stringified and
        # stored as constant this the default behavior under Python 3.10
        if sys.version_info >= (3, 10):
            func_code = concrete.consts[3]
            names = ["foo"]
            consts = ["x", "int", "y", func_code, "foo", None, ("x", "int", "y", "int")]
        elif concrete.flags & CompilerFlags.FUTURE_ANNOTATIONS:
            func_code = concrete.consts[2]
            names = ["foo"]
            consts = ["int", ("x", "y"), func_code, "foo", None]
        else:
            func_code = concrete.consts[1]
            names = ["int", "foo"]
            consts = [("x", "y"), func_code, "foo", None]

        self.assertEqual(concrete.names, names)
        self.assertEqual(concrete.consts, consts)
        self.assertListEqual(list(concrete), expected)
Beispiel #25
0
def f(a, b):
    #    res = a + b
    return


def g(a, b):
    res = a + b if a < b else b + a
    r = 0
    for a in range(res):
        r += 1
    return r or 2


for x in (f, g):
    #get byte code for f
    dis(x)
    print(f.__code__.co_code)
    c = Bytecode.from_code(x.__code__)
    cc = ConcreteBytecode.from_code(x.__code__)
    dump_bytecode(c)
    dump_bytecode(cc)

    #generate byte code
    cnew = c.to_code()

    x.__code__ = cnew
    dis(x)

    print(x(3, 5))
Beispiel #26
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc['func']
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(ConcreteBytecode.from_code(code).to_code().co_code,
                         code.co_code)
Beispiel #27
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc["func"]
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(
            ConcreteBytecode.from_code(code).to_code().co_code, code.co_code
        )
Beispiel #28
0
    def test_expected_arg_with_many_consts(self):
        def test():
            var = 0
            var = 1
            var = 2
            var = 3
            var = 4
            var = 5
            var = 6
            var = 7
            var = 8
            var = 9
            var = 10
            var = 11
            var = 12
            var = 13
            var = 14
            var = 15
            var = 16
            var = 17
            var = 18
            var = 19
            var = 20
            var = 21
            var = 22
            var = 23
            var = 24
            var = 25
            var = 26
            var = 27
            var = 28
            var = 29
            var = 30
            var = 31
            var = 32
            var = 33
            var = 34
            var = 35
            var = 36
            var = 37
            var = 38
            var = 39
            var = 40
            var = 41
            var = 42
            var = 43
            var = 44
            var = 45
            var = 46
            var = 47
            var = 48
            var = 49
            var = 50
            var = 51
            var = 52
            var = 53
            var = 54
            var = 55
            var = 56
            var = 57
            var = 58
            var = 59
            var = 60
            var = 61
            var = 62
            var = 63
            var = 64
            var = 65
            var = 66
            var = 67
            var = 68
            var = 69
            var = 70
            var = 71
            var = 72
            var = 73
            var = 74
            var = 75
            var = 76
            var = 77
            var = 78
            var = 79
            var = 80
            var = 81
            var = 82
            var = 83
            var = 84
            var = 85
            var = 86
            var = 87
            var = 88
            var = 89
            var = 90
            var = 91
            var = 92
            var = 93
            var = 94
            var = 95
            var = 96
            var = 97
            var = 98
            var = 99
            var = 100
            var = 101
            var = 102
            var = 103
            var = 104
            var = 105
            var = 106
            var = 107
            var = 108
            var = 109
            var = 110
            var = 111
            var = 112
            var = 113
            var = 114
            var = 115
            var = 116
            var = 117
            var = 118
            var = 119
            var = 120
            var = 121
            var = 122
            var = 123
            var = 124
            var = 125
            var = 126
            var = 127
            var = 128
            var = 129
            var = 130
            var = 131
            var = 132
            var = 133
            var = 134
            var = 135
            var = 136
            var = 137
            var = 138
            var = 139
            var = 140
            var = 141
            var = 142
            var = 143
            var = 144
            var = 145
            var = 146
            var = 147
            var = 148
            var = 149
            var = 150
            var = 151
            var = 152
            var = 153
            var = 154
            var = 155
            var = 156
            var = 157
            var = 158
            var = 159
            var = 160
            var = 161
            var = 162
            var = 163
            var = 164
            var = 165
            var = 166
            var = 167
            var = 168
            var = 169
            var = 170
            var = 171
            var = 172
            var = 173
            var = 174
            var = 175
            var = 176
            var = 177
            var = 178
            var = 179
            var = 180
            var = 181
            var = 182
            var = 183
            var = 184
            var = 185
            var = 186
            var = 187
            var = 188
            var = 189
            var = 190
            var = 191
            var = 192
            var = 193
            var = 194
            var = 195
            var = 196
            var = 197
            var = 198
            var = 199
            var = 200
            var = 201
            var = 202
            var = 203
            var = 204
            var = 205
            var = 206
            var = 207
            var = 208
            var = 209
            var = 210
            var = 211
            var = 212
            var = 213
            var = 214
            var = 215
            var = 216
            var = 217
            var = 218
            var = 219
            var = 220
            var = 221
            var = 222
            var = 223
            var = 224
            var = 225
            var = 226
            var = 227
            var = 228
            var = 229
            var = 230
            var = 231
            var = 232
            var = 233
            var = 234
            var = 235
            var = 236
            var = 237
            var = 238
            var = 239
            var = 240
            var = 241
            var = 242
            var = 243
            var = 244
            var = 245
            var = 246
            var = 247
            var = 248
            var = 249
            var = 250
            var = 251
            var = 252
            var = 253
            var = 254
            var = 255
            var = 256
            var = 257
            var = 258
            var = 259

            return var

        test.__code__ = ConcreteBytecode.from_code(
            test.__code__, extended_arg=True
        ).to_code()
        self.assertEqual(test.__code__.co_stacksize, 1)
        self.assertEqual(test(), 259)
Beispiel #29
0
        def test_fail_extended_arg_jump(self):
            def test():
                var = None
                for _ in range(0, 1):
                    var = 0
                    var = 1
                    var = 2
                    var = 3
                    var = 4
                    var = 5
                    var = 6
                    var = 7
                    var = 8
                    var = 9
                    var = 10
                    var = 11
                    var = 12
                    var = 13
                    var = 14
                    var = 15
                    var = 16
                    var = 17
                    var = 18
                    var = 19
                    var = 20
                    var = 21
                    var = 22
                    var = 23
                    var = 24
                    var = 25
                    var = 26
                    var = 27
                    var = 28
                    var = 29
                    var = 30
                    var = 31
                    var = 32
                    var = 33
                    var = 34
                    var = 35
                    var = 36
                    var = 37
                    var = 38
                    var = 39
                    var = 40
                    var = 41
                    var = 42
                    var = 43
                    var = 44
                    var = 45
                    var = 46
                    var = 47
                    var = 48
                    var = 49
                    var = 50
                    var = 51
                    var = 52
                    var = 53
                    var = 54
                    var = 55
                    var = 56
                    var = 57
                    var = 58
                    var = 59
                    var = 60
                    var = 61
                    var = 62
                    var = 63
                    var = 64
                    var = 65
                    var = 66
                    var = 67
                    var = 68
                    var = 69
                    var = 70
                return var

            # Generate the bytecode with extended arguments
            bytecode = ConcreteBytecode.from_code(test.__code__, extended_arg=True)
            bytecode.to_code()
Beispiel #30
0
        def test_fail_extended_arg_jump(self):
            def test():
                var = None
                for _ in range(0, 1):
                    var = 0
                    var = 1
                    var = 2
                    var = 3
                    var = 4
                    var = 5
                    var = 6
                    var = 7
                    var = 8
                    var = 9
                    var = 10
                    var = 11
                    var = 12
                    var = 13
                    var = 14
                    var = 15
                    var = 16
                    var = 17
                    var = 18
                    var = 19
                    var = 20
                    var = 21
                    var = 22
                    var = 23
                    var = 24
                    var = 25
                    var = 26
                    var = 27
                    var = 28
                    var = 29
                    var = 30
                    var = 31
                    var = 32
                    var = 33
                    var = 34
                    var = 35
                    var = 36
                    var = 37
                    var = 38
                    var = 39
                    var = 40
                    var = 41
                    var = 42
                    var = 43
                    var = 44
                    var = 45
                    var = 46
                    var = 47
                    var = 48
                    var = 49
                    var = 50
                    var = 51
                    var = 52
                    var = 53
                    var = 54
                    var = 55
                    var = 56
                    var = 57
                    var = 58
                    var = 59
                    var = 60
                    var = 61
                    var = 62
                    var = 63
                    var = 64
                    var = 65
                    var = 66
                    var = 67
                    var = 68
                    var = 69
                    var = 70
                return var

            # Generate the bytecode with extended arguments
            bytecode = ConcreteBytecode.from_code(test.__code__, extended_arg=True)
            # This is where computation fails
            # It seems like it is caused by the split of blocks and a wrong start size
            # for one block.
            bytecode.to_code()