diff options
author | Pablo Galindo <Pablogsal@gmail.com> | 2019-05-09 15:52:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-09 15:52:02 (GMT) |
commit | f00828a742d2e88c910bdfd00f08fcd998554ba5 (patch) | |
tree | 3a8b1c942d314019153162b4b56860556eae3a68 /Lib/test/test_code.py | |
parent | 33e067d6a237ced8fd2ead70a461025fd91239be (diff) | |
download | cpython-f00828a742d2e88c910bdfd00f08fcd998554ba5.zip cpython-f00828a742d2e88c910bdfd00f08fcd998554ba5.tar.gz cpython-f00828a742d2e88c910bdfd00f08fcd998554ba5.tar.bz2 |
bpo-36851: Clean the frame stack if the execution ends with a return and the stack is not empty (GH-13191)
Diffstat (limited to 'Lib/test/test_code.py')
-rw-r--r-- | Lib/test/test_code.py | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index e49121e..9bf290d 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -130,6 +130,7 @@ import sys import threading import unittest import weakref +import opcode try: import ctypes except ImportError: @@ -379,6 +380,43 @@ if check_impl_detail(cpython=True) and ctypes is not None: tt.join() self.assertEqual(LAST_FREED, 500) + @cpython_only + def test_clean_stack_on_return(self): + + def f(x): + return x + + code = f.__code__ + ct = type(f.__code__) + + # Insert an extra LOAD_FAST, this duplicates the value of + # 'x' in the stack, leaking it if the frame is not properly + # cleaned up upon exit. + + bytecode = list(code.co_code) + bytecode.insert(-2, opcode.opmap['LOAD_FAST']) + bytecode.insert(-2, 0) + + c = ct(code.co_argcount, code.co_posonlyargcount, + code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize+1, + code.co_flags, bytes(bytecode), + 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) + new_function = type(f)(c, f.__globals__, 'nf', f.__defaults__, f.__closure__) + + class Var: + pass + the_object = Var() + var = weakref.ref(the_object) + + new_function(the_object) + + # Check if the_object is leaked + del the_object + assert var() is None + + def test_main(verbose=None): from test import test_code run_doctest(test_code, verbose) |