diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2021-06-08 22:01:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-08 22:01:34 (GMT) |
commit | 3e1c7167d86a2a928cdcb659094aa10bb5550c4c (patch) | |
tree | b3b071ff5636c7c5edd8d536b8732c6a2259a44c /Lib | |
parent | ab36b9f83424a020fbd672f218612e6f19257a32 (diff) | |
download | cpython-3e1c7167d86a2a928cdcb659094aa10bb5550c4c.zip cpython-3e1c7167d86a2a928cdcb659094aa10bb5550c4c.tar.gz cpython-3e1c7167d86a2a928cdcb659094aa10bb5550c4c.tar.bz2 |
bpo-43693: Un-revert commit f3fa63e. (#26609)
This was reverted in GH-26596 (commit 6d518bb) due to some bad memory accesses.
* Add the MAKE_CELL opcode. (gh-26396)
The memory accesses have been fixed.
https://bugs.python.org/issue43693
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 3 | ||||
-rw-r--r-- | Lib/opcode.py | 10 | ||||
-rw-r--r-- | Lib/test/test_dis.py | 131 | ||||
-rw-r--r-- | Lib/test/test_scope.py | 51 |
4 files changed, 129 insertions, 66 deletions
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3955218..009b45f 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -357,6 +357,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a1 3452 (drop nlocals from marshaled code objects) # Python 3.11a1 3453 (add co_fastlocalnames and co_fastlocalkinds) # Python 3.11a1 3454 (compute cell offsets relative to locals bpo-43693) +# Python 3.11a1 3455 (add MAKE_CELL bpo-43693) # # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -366,7 +367,7 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3454).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3455).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index da143fe..4d53431 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -181,14 +181,16 @@ def_op('CALL_FUNCTION', 131) # #args def_op('MAKE_FUNCTION', 132) # Flags def_op('BUILD_SLICE', 133) # Number of items -def_op('LOAD_CLOSURE', 135) +def_op('MAKE_CELL', 135) hasfree.append(135) -def_op('LOAD_DEREF', 136) +def_op('LOAD_CLOSURE', 136) hasfree.append(136) -def_op('STORE_DEREF', 137) +def_op('LOAD_DEREF', 137) hasfree.append(137) -def_op('DELETE_DEREF', 138) +def_op('STORE_DEREF', 138) hasfree.append(138) +def_op('DELETE_DEREF', 139) +hasfree.append(139) def_op('CALL_FUNCTION_KW', 141) # #args + #kwargs def_op('CALL_FUNCTION_EX', 142) # Flags diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b119d18..b81fcb5 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -427,15 +427,17 @@ def _h(y): return foo dis_nested_0 = """\ -%3d 0 LOAD_CLOSURE 2 (y) - 2 BUILD_TUPLE 1 - 4 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>) - 6 LOAD_CONST 2 ('_h.<locals>.foo') - 8 MAKE_FUNCTION 8 (closure) - 10 STORE_FAST 1 (foo) - -%3d 12 LOAD_FAST 1 (foo) - 14 RETURN_VALUE + 0 MAKE_CELL 2 (y) + +%3d 2 LOAD_CLOSURE 2 (y) + 4 BUILD_TUPLE 1 + 6 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>) + 8 LOAD_CONST 2 ('_h.<locals>.foo') + 10 MAKE_FUNCTION 8 (closure) + 12 STORE_FAST 1 (foo) + +%3d 14 LOAD_FAST 1 (foo) + 16 RETURN_VALUE """ % (_h.__code__.co_firstlineno + 1, __file__, _h.__code__.co_firstlineno + 1, @@ -444,15 +446,17 @@ dis_nested_0 = """\ dis_nested_1 = """%s Disassembly of <code object foo at 0x..., file "%s", line %d>: -%3d 0 LOAD_CLOSURE 1 (x) - 2 BUILD_TUPLE 1 - 4 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) - 6 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>') - 8 MAKE_FUNCTION 8 (closure) - 10 LOAD_DEREF 2 (y) - 12 GET_ITER - 14 CALL_FUNCTION 1 - 16 RETURN_VALUE + 0 MAKE_CELL 1 (x) + +%3d 2 LOAD_CLOSURE 1 (x) + 4 BUILD_TUPLE 1 + 6 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) + 8 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>') + 10 MAKE_FUNCTION 8 (closure) + 12 LOAD_DEREF 2 (y) + 14 GET_ITER + 16 CALL_FUNCTION 1 + 18 RETURN_VALUE """ % (dis_nested_0, __file__, _h.__code__.co_firstlineno + 1, @@ -958,59 +962,64 @@ expected_jumpy_line = 1 #print('expected_opinfo_jumpy = [\n ', #',\n '.join(map(str, _instructions)), ',\n]', sep='') +#dis.dis(outer) Instruction = dis.Instruction expected_opinfo_outer = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=10, starts_line=None, is_jump_target=False), - Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=12, starts_line=None, is_jump_target=False), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=16, starts_line=7, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False), - Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=32, starts_line=None, is_jump_target=False), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=36, starts_line=8, is_jump_target=False), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CELL', opcode=135, arg=3, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CELL', opcode=135, arg=4, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=4, starts_line=2, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=10, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=14, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=7, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=26, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=28, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=32, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=34, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=40, starts_line=8, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False), ] expected_opinfo_f = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=5, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=6, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=14, starts_line=None, is_jump_target=False), - Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=18, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=5, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=5, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=6, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False), - Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=30, starts_line=None, is_jump_target=False), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=34, starts_line=6, is_jump_target=False), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CELL', opcode=135, arg=3, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CELL', opcode=135, arg=4, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=4, starts_line=3, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=5, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=6, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=14, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=16, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=20, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=22, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=5, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=6, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False), ] expected_opinfo_inner = [ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=5, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False), diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py index 4239b26..29d60ff 100644 --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -176,6 +176,57 @@ class ScopeTests(unittest.TestCase): self.assertEqual(foo(a=42), 50) self.assertEqual(foo(), 25) + def testCellIsArgAndEscapes(self): + # We need to be sure that a cell passed in as an arg still + # gets wrapped in a new cell if the arg escapes into an + # inner function (closure). + + def external(): + value = 42 + def inner(): + return value + cell, = inner.__closure__ + return cell + cell_ext = external() + + def spam(arg): + def eggs(): + return arg + return eggs + + eggs = spam(cell_ext) + cell_closure, = eggs.__closure__ + cell_eggs = eggs() + + self.assertIs(cell_eggs, cell_ext) + self.assertIsNot(cell_eggs, cell_closure) + + def testCellIsLocalAndEscapes(self): + # We need to be sure that a cell bound to a local still + # gets wrapped in a new cell if the local escapes into an + # inner function (closure). + + def external(): + value = 42 + def inner(): + return value + cell, = inner.__closure__ + return cell + cell_ext = external() + + def spam(arg): + cell = arg + def eggs(): + return cell + return eggs + + eggs = spam(cell_ext) + cell_closure, = eggs.__closure__ + cell_eggs = eggs() + + self.assertIs(cell_eggs, cell_ext) + self.assertIsNot(cell_eggs, cell_closure) + def testRecursion(self): def f(x): |