diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2019-09-27 14:53:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-27 14:53:34 (GMT) |
commit | 6693f730e0eb77d9453f73a3da33b78a97e996ee (patch) | |
tree | 767d8adedbf3db4c89a1b74d030d1b563e4199fb /Lib/test/test_tools | |
parent | 90558158093c0ad893102158fd3c2dd9f864e82e (diff) | |
download | cpython-6693f730e0eb77d9453f73a3da33b78a97e996ee.zip cpython-6693f730e0eb77d9453f73a3da33b78a97e996ee.tar.gz cpython-6693f730e0eb77d9453f73a3da33b78a97e996ee.tar.bz2 |
bpo-38187: Fix a refleak in Tools/c-analyzer. (gh-16304)
The "Slot" helper (descriptor) is leaking references due to its caching mechanism. The change includes a partial fix to Slot, but also adds Variable.storage to replace the problematic use of Slot.
https://bugs.python.org/issue38187
Diffstat (limited to 'Lib/test/test_tools')
7 files changed, 100 insertions, 40 deletions
diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/__init__.py index e69de29..bc502ef 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/__init__.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/__init__.py @@ -0,0 +1,6 @@ +import os.path +from test.support import load_package_tests + + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/test_known.py b/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/test_known.py index 93100e0..215023d 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/test_known.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_analyzer_common/test_known.py @@ -15,9 +15,6 @@ class FromFileTests(unittest.TestCase): _return_read_tsv = () - def tearDown(self): - Variable._isglobal.instances.clear() - @property def calls(self): try: diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_globals/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_c_globals/__init__.py index e69de29..bc502ef 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_globals/__init__.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_globals/__init__.py @@ -0,0 +1,6 @@ +import os.path +from test.support import load_package_tests + + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_globals/test_find.py b/Lib/test/test_tools/test_c_analyzer/test_c_globals/test_find.py index b29f966..8288992 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_globals/test_find.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_globals/test_find.py @@ -64,7 +64,9 @@ class StaticsFromBinaryTests(_Base): **self.kwargs)) self.assertEqual(found, [ + info.Variable.from_parts('dir1/spam.c', None, 'var1', 'int'), info.Variable.from_parts('dir1/spam.c', None, 'var2', 'static int'), + info.Variable.from_parts('dir1/spam.c', None, 'var3', 'char *'), info.Variable.from_parts('dir1/eggs.c', None, 'var1', 'static int'), info.Variable.from_parts('dir1/eggs.c', 'func1', 'var2', 'static char *'), ]) @@ -299,7 +301,7 @@ class StaticsTest(_Base): info.Variable.from_parts('src1/spam.c', None, 'var1', 'static const char *'), info.Variable.from_parts('src1/spam.c', None, 'var1b', 'const char *'), info.Variable.from_parts('src1/spam.c', 'ham', 'initialized', 'static int'), - info.Variable.from_parts('src1/spam.c', 'ham', 'result', 'int'), + info.Variable.from_parts('src1/spam.c', 'ham', 'result', 'int'), # skipped info.Variable.from_parts('src1/spam.c', None, 'var2', 'static PyObject *'), info.Variable.from_parts('src1/eggs.c', 'tofu', 'ready', 'static int'), info.Variable.from_parts('src1/spam.c', None, 'freelist', 'static (PyTupleObject *)[10]'), @@ -318,6 +320,7 @@ class StaticsTest(_Base): self.assertEqual(found, [ info.Variable.from_parts('src1/spam.c', None, 'var1', 'static const char *'), + info.Variable.from_parts('src1/spam.c', None, 'var1b', 'const char *'), info.Variable.from_parts('src1/spam.c', 'ham', 'initialized', 'static int'), info.Variable.from_parts('src1/spam.c', None, 'var2', 'static PyObject *'), info.Variable.from_parts('src1/eggs.c', 'tofu', 'ready', 'static int'), diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_parser/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_c_parser/__init__.py index e69de29..bc502ef 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_parser/__init__.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_parser/__init__.py @@ -0,0 +1,6 @@ +import os.path +from test.support import load_package_tests + + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_parser/test_info.py b/Lib/test/test_tools/test_c_analyzer/test_c_parser/test_info.py index 1dfe5d0..d1a966c 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_parser/test_info.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_parser/test_info.py @@ -4,7 +4,7 @@ import unittest from ..util import PseudoStr, StrProxy, Object from .. import tool_imports_for_tests with tool_imports_for_tests(): - from c_analyzer_common.info import ID + from c_analyzer_common.info import ID, UNKNOWN from c_parser.info import ( normalize_vartype, Variable, ) @@ -31,38 +31,47 @@ class VariableTests(unittest.TestCase): VALID_ARGS = ( ('x/y/z/spam.c', 'func', 'eggs'), + 'static', 'int', ) VALID_KWARGS = dict(zip(Variable._fields, VALID_ARGS)) VALID_EXPECTED = VALID_ARGS def test_init_typical_global(self): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname=None, - name='eggs', - ), - vartype='int', - ) + for storage in ('static', 'extern', 'implicit'): + with self.subTest(storage): + static = Variable( + id=ID( + filename='x/y/z/spam.c', + funcname=None, + name='eggs', + ), + storage=storage, + vartype='int', + ) - self.assertEqual(static, ( - ('x/y/z/spam.c', None, 'eggs'), - 'int', - )) + self.assertEqual(static, ( + ('x/y/z/spam.c', None, 'eggs'), + storage, + 'int', + )) def test_init_typical_local(self): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ), - vartype='int', - ) + for storage in ('static', 'local'): + with self.subTest(storage): + static = Variable( + id=ID( + filename='x/y/z/spam.c', + funcname='func', + name='eggs', + ), + storage=storage, + vartype='int', + ) self.assertEqual(static, ( ('x/y/z/spam.c', 'func', 'eggs'), + storage, 'int', )) @@ -71,12 +80,14 @@ class VariableTests(unittest.TestCase): with self.subTest(repr(value)): static = Variable( id=value, + storage=value, vartype=value, ) self.assertEqual(static, ( None, None, + None, )) def test_init_all_coerced(self): @@ -89,34 +100,42 @@ class VariableTests(unittest.TestCase): PseudoStr('func'), PseudoStr('spam'), ), + storage=PseudoStr('static'), vartype=PseudoStr('int'), ), (id, + 'static', 'int', )), ('non-str 1', dict( id=id, + storage=Object(), vartype=Object(), ), (id, '<object>', + '<object>', )), ('non-str 2', dict( id=id, + storage=StrProxy('static'), vartype=StrProxy('variable'), ), (id, + 'static', 'variable', )), ('non-str', dict( id=id, - vartype=('a', 'b', 'c'), + storage=('a', 'b', 'c'), + vartype=('x', 'y', 'z'), ), (id, "('a', 'b', 'c')", + "('x', 'y', 'z')", )), ] for summary, kwargs, expected in tests: @@ -134,36 +153,43 @@ class VariableTests(unittest.TestCase): def test_iterable(self): static = Variable(**self.VALID_KWARGS) - id, vartype = static + id, storage, vartype = static - values = (id, vartype) + values = (id, storage, vartype) for value, expected in zip(values, self.VALID_EXPECTED): self.assertEqual(value, expected) def test_fields(self): - static = Variable(('a', 'b', 'z'), 'x') + static = Variable(('a', 'b', 'z'), 'x', 'y') self.assertEqual(static.id, ('a', 'b', 'z')) - self.assertEqual(static.vartype, 'x') + self.assertEqual(static.storage, 'x') + self.assertEqual(static.vartype, 'y') def test___getattr__(self): - static = Variable(('a', 'b', 'z'), 'x') + static = Variable(('a', 'b', 'z'), 'x', 'y') self.assertEqual(static.filename, 'a') self.assertEqual(static.funcname, 'b') self.assertEqual(static.name, 'z') def test_validate_typical(self): - static = Variable( - id=ID( - filename='x/y/z/spam.c', - funcname='func', - name='eggs', - ), - vartype='int', - ) + validstorage = ('static', 'extern', 'implicit', 'local') + self.assertEqual(set(validstorage), set(Variable.STORAGE)) + + for storage in validstorage: + with self.subTest(storage): + static = Variable( + id=ID( + filename='x/y/z/spam.c', + funcname='func', + name='eggs', + ), + storage=storage, + vartype='int', + ) - static.validate() # This does not fail. + static.validate() # This does not fail. def test_validate_missing_field(self): for field in Variable._fields: @@ -173,6 +199,13 @@ class VariableTests(unittest.TestCase): with self.assertRaises(TypeError): static.validate() + for field in ('storage', 'vartype'): + with self.subTest(field): + static = Variable(**self.VALID_KWARGS) + static = static._replace(**{field: UNKNOWN}) + + with self.assertRaises(TypeError): + static.validate() def test_validate_bad_field(self): badch = tuple(c for c in string.punctuation + string.digits) @@ -185,6 +218,7 @@ class VariableTests(unittest.TestCase): ) + badch tests = [ ('id', ()), # Any non-empty str is okay. + ('storage', ('external', 'global') + notnames), ('vartype', ()), # Any non-empty str is okay. ] seen = set() @@ -199,6 +233,8 @@ class VariableTests(unittest.TestCase): static.validate() for field, invalid in tests: + if field == 'id': + continue valid = seen - set(invalid) for value in valid: with self.subTest(f'{field}={value!r}'): diff --git a/Lib/test/test_tools/test_c_analyzer/test_c_symbols/__init__.py b/Lib/test/test_tools/test_c_analyzer/test_c_symbols/__init__.py index e69de29..bc502ef 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_c_symbols/__init__.py +++ b/Lib/test/test_tools/test_c_analyzer/test_c_symbols/__init__.py @@ -0,0 +1,6 @@ +import os.path +from test.support import load_package_tests + + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) |