mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-117174: Fix reference leak and gdb tests (#131095)
This commit is contained in:
parent
c00ac57824
commit
ebc24d54bc
8 changed files with 88 additions and 83 deletions
|
|
@ -51,9 +51,11 @@ def _getline_from_code(filename, lineno):
|
|||
return lines[lineno - 1]
|
||||
return ''
|
||||
|
||||
def _make_key(code):
|
||||
return (code.co_filename, code.co_qualname, code.co_firstlineno)
|
||||
|
||||
def _getlines_from_code(code):
|
||||
code_id = id(code)
|
||||
code_id = _make_key(code)
|
||||
if code_id in _interactive_cache:
|
||||
entry = _interactive_cache[code_id]
|
||||
if len(entry) != 1:
|
||||
|
|
@ -215,7 +217,6 @@ def get_lines(name=name, *args, **kwargs):
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _register_code(code, string, name):
|
||||
entry = (len(string),
|
||||
None,
|
||||
|
|
@ -227,4 +228,4 @@ def _register_code(code, string, name):
|
|||
for const in code.co_consts:
|
||||
if isinstance(const, type(code)):
|
||||
stack.append(const)
|
||||
_interactive_cache[id(code)] = entry
|
||||
_interactive_cache[_make_key(code)] = entry
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import warnings
|
||||
from inspect import isabstract
|
||||
from typing import Any
|
||||
import linecache
|
||||
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
|
|
@ -73,6 +74,11 @@ def runtest_refleak(test_name, test_func,
|
|||
ps = copyreg.dispatch_table.copy()
|
||||
pic = sys.path_importer_cache.copy()
|
||||
zdc: dict[str, Any] | None
|
||||
# Linecache holds a cache with the source of interactive code snippets
|
||||
# (e.g. code typed in the REPL). This cache is not cleared by
|
||||
# linecache.clearcache(). We need to save and restore it to avoid false
|
||||
# positives.
|
||||
linecache_data = linecache.cache.copy(), linecache._interactive_cache.copy() # type: ignore[attr-defined]
|
||||
try:
|
||||
import zipimport
|
||||
except ImportError:
|
||||
|
|
@ -122,7 +128,7 @@ def get_pooled_int(value):
|
|||
|
||||
xml_filename = 'refleak-xml.tmp'
|
||||
result = None
|
||||
dash_R_cleanup(fs, ps, pic, zdc, abcs)
|
||||
dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data)
|
||||
|
||||
for i in rep_range:
|
||||
support.gc_collect()
|
||||
|
|
@ -134,7 +140,7 @@ def get_pooled_int(value):
|
|||
refleak_helper._hunting_for_refleaks = current
|
||||
|
||||
save_support_xml(xml_filename)
|
||||
dash_R_cleanup(fs, ps, pic, zdc, abcs)
|
||||
dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data)
|
||||
support.gc_collect()
|
||||
|
||||
# Read memory statistics immediately after the garbage collection.
|
||||
|
|
@ -223,7 +229,7 @@ def check_fd_deltas(deltas):
|
|||
return (failed, result)
|
||||
|
||||
|
||||
def dash_R_cleanup(fs, ps, pic, zdc, abcs):
|
||||
def dash_R_cleanup(fs, ps, pic, zdc, abcs, linecache_data):
|
||||
import copyreg
|
||||
import collections.abc
|
||||
|
||||
|
|
@ -233,6 +239,11 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
|
|||
copyreg.dispatch_table.update(ps)
|
||||
sys.path_importer_cache.clear()
|
||||
sys.path_importer_cache.update(pic)
|
||||
lcache, linteractive = linecache_data
|
||||
linecache._interactive_cache.clear()
|
||||
linecache._interactive_cache.update(linteractive)
|
||||
linecache.cache.clear()
|
||||
linecache.cache.update(lcache)
|
||||
try:
|
||||
import zipimport
|
||||
except ImportError:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# Sample script for use by test_gdb
|
||||
from _typing import _idfunc
|
||||
|
||||
def foo(a, b, c):
|
||||
bar(a=a, b=b, c=c)
|
||||
|
|
@ -8,6 +7,6 @@ def bar(a, b, c):
|
|||
baz(a, b, c)
|
||||
|
||||
def baz(*args):
|
||||
_idfunc(42)
|
||||
id(42)
|
||||
|
||||
foo(1, 2, 3)
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ def test_bt(self):
|
|||
self.assertMultilineMatches(bt,
|
||||
r'''^.*
|
||||
Traceback \(most recent call first\):
|
||||
<built-in method _idfunc of module object .*>
|
||||
File ".*gdb_sample.py", line 11, in baz
|
||||
_idfunc\(42\)
|
||||
File ".*gdb_sample.py", line 8, in bar
|
||||
<built-in method id of module object .*>
|
||||
File ".*gdb_sample.py", line 10, in baz
|
||||
id\(42\)
|
||||
File ".*gdb_sample.py", line 7, in bar
|
||||
baz\(a, b, c\)
|
||||
File ".*gdb_sample.py", line 5, in foo
|
||||
File ".*gdb_sample.py", line 4, in foo
|
||||
bar\(a=a, b=b, c=c\)
|
||||
File ".*gdb_sample.py", line 13, in <module>
|
||||
File ".*gdb_sample.py", line 12, in <module>
|
||||
foo\(1, 2, 3\)
|
||||
''')
|
||||
|
||||
|
|
@ -39,11 +39,11 @@ def test_bt_full(self):
|
|||
cmds_after_breakpoint=['py-bt-full'])
|
||||
self.assertMultilineMatches(bt,
|
||||
r'''^.*
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 8, in bar \(a=1, b=2, c=3\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\)
|
||||
baz\(a, b, c\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 5, in foo \(a=1, b=2, c=3\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\)
|
||||
bar\(a=a, b=b, c=c\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 13, in <module> \(\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in <module> \(\)
|
||||
foo\(1, 2, 3\)
|
||||
''')
|
||||
|
||||
|
|
@ -55,7 +55,6 @@ def test_threads(self):
|
|||
'Verify that "py-bt" indicates threads that are waiting for the GIL'
|
||||
cmd = '''
|
||||
from threading import Thread
|
||||
from _typing import _idfunc
|
||||
|
||||
class TestThread(Thread):
|
||||
# These threads would run forever, but we'll interrupt things with the
|
||||
|
|
@ -71,7 +70,7 @@ def run(self):
|
|||
t[i].start()
|
||||
|
||||
# Trigger a breakpoint on the main thread
|
||||
_idfunc(42)
|
||||
id(42)
|
||||
|
||||
'''
|
||||
# Verify with "py-bt":
|
||||
|
|
@ -91,8 +90,8 @@ def run(self):
|
|||
# unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
|
||||
def test_gc(self):
|
||||
'Verify that "py-bt" indicates if a thread is garbage-collecting'
|
||||
cmd = ('from gc import collect; from _typing import _idfunc\n'
|
||||
'_idfunc(42)\n'
|
||||
cmd = ('from gc import collect\n'
|
||||
'id(42)\n'
|
||||
'def foo():\n'
|
||||
' collect()\n'
|
||||
'def bar():\n'
|
||||
|
|
@ -114,12 +113,11 @@ def test_gc(self):
|
|||
"Python was compiled with optimizations")
|
||||
def test_wrapper_call(self):
|
||||
cmd = textwrap.dedent('''
|
||||
from typing import _idfunc
|
||||
class MyList(list):
|
||||
def __init__(self):
|
||||
super(*[]).__init__() # wrapper_call()
|
||||
|
||||
_idfunc("first break point")
|
||||
id("first break point")
|
||||
l = MyList()
|
||||
''')
|
||||
cmds_after_breakpoint = ['break wrapper_call', 'continue']
|
||||
|
|
|
|||
|
|
@ -35,14 +35,14 @@ def test_basic_command(self):
|
|||
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
||||
cmds_after_breakpoint=['py-list'])
|
||||
|
||||
self.assertListing(' 6 \n'
|
||||
' 7 def bar(a, b, c):\n'
|
||||
' 8 baz(a, b, c)\n'
|
||||
' 9 \n'
|
||||
' 10 def baz(*args):\n'
|
||||
' >11 _idfunc(42)\n'
|
||||
' 12 \n'
|
||||
' 13 foo(1, 2, 3)\n',
|
||||
self.assertListing(' 5 \n'
|
||||
' 6 def bar(a, b, c):\n'
|
||||
' 7 baz(a, b, c)\n'
|
||||
' 8 \n'
|
||||
' 9 def baz(*args):\n'
|
||||
' >10 id(42)\n'
|
||||
' 11 \n'
|
||||
' 12 foo(1, 2, 3)\n',
|
||||
bt)
|
||||
|
||||
def test_one_abs_arg(self):
|
||||
|
|
@ -50,27 +50,25 @@ def test_one_abs_arg(self):
|
|||
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
||||
cmds_after_breakpoint=['py-list 9'])
|
||||
|
||||
self.assertListing(' 10 def baz(*args):\n'
|
||||
' >11 _idfunc(42)\n'
|
||||
' 12 \n'
|
||||
' 13 foo(1, 2, 3)\n',
|
||||
self.assertListing(' 9 def baz(*args):\n'
|
||||
' >10 id(42)\n'
|
||||
' 11 \n'
|
||||
' 12 foo(1, 2, 3)\n',
|
||||
bt)
|
||||
|
||||
def test_two_abs_args(self):
|
||||
'Verify the "py-list" command with two absolute arguments'
|
||||
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
||||
cmds_after_breakpoint=['py-list 1,4'])
|
||||
cmds_after_breakpoint=['py-list 1,3'])
|
||||
|
||||
self.assertListing(' 1 # Sample script for use by test_gdb\n'
|
||||
' 2 from _typing import _idfunc\n'
|
||||
' 3 \n'
|
||||
' 4 def foo(a, b, c):\n',
|
||||
' 2 \n'
|
||||
' 3 def foo(a, b, c):\n',
|
||||
bt)
|
||||
|
||||
SAMPLE_WITH_C_CALL = """
|
||||
|
||||
from _testcapi import pyobject_vectorcall
|
||||
from _typing import _idfunc
|
||||
|
||||
def foo(a, b, c):
|
||||
bar(a, b, c)
|
||||
|
|
@ -79,7 +77,7 @@ def bar(a, b, c):
|
|||
pyobject_vectorcall(baz, (a, b, c), None)
|
||||
|
||||
def baz(*args):
|
||||
_idfunc(42)
|
||||
id(42)
|
||||
|
||||
foo(1, 2, 3)
|
||||
|
||||
|
|
@ -96,7 +94,7 @@ def test_pyup_command(self):
|
|||
cmds_after_breakpoint=['py-up', 'py-up'])
|
||||
self.assertMultilineMatches(bt,
|
||||
r'''^.*
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 13, in baz \(args=\(1, 2, 3\)\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
||||
#[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
|
||||
$''')
|
||||
|
||||
|
|
@ -125,9 +123,9 @@ def test_up_then_down(self):
|
|||
cmds_after_breakpoint=['py-up', 'py-up', 'py-down'])
|
||||
self.assertMultilineMatches(bt,
|
||||
r'''^.*
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 13, in baz \(args=\(1, 2, 3\)\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
||||
#[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 13, in baz \(args=\(1, 2, 3\)\)
|
||||
#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
|
||||
$''')
|
||||
|
||||
class PyPrintTests(DebuggerTests):
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ def get_gdb_repr(self, source,
|
|||
import_site=False):
|
||||
# Given an input python source representation of data,
|
||||
# run "python -c'id(DATA)'" under gdb with a breakpoint on
|
||||
# _typing__idfunc and scrape out gdb's representation of the "op"
|
||||
# builtin_id and scrape out gdb's representation of the "op"
|
||||
# parameter, and verify that the gdb displays the same string
|
||||
#
|
||||
# Verify that the gdb displays the expected string
|
||||
|
|
@ -29,7 +29,6 @@ def get_gdb_repr(self, source,
|
|||
# undecodable characters may lurk there in optimized mode
|
||||
# (issue #19743).
|
||||
cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"]
|
||||
source = "from _typing import _idfunc\n" + source
|
||||
gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN,
|
||||
cmds_after_breakpoint=cmds_after_breakpoint,
|
||||
import_site=import_site)
|
||||
|
|
@ -37,10 +36,10 @@ def get_gdb_repr(self, source,
|
|||
# in its output, depending on the width of the terminal it's connected
|
||||
# to (using its "wrap_here" function)
|
||||
m = re.search(
|
||||
# Match '#0 _typing_idfunc(module=..., x=...)'
|
||||
r'#0\s+_typing__idfunc\s+\(module\=.*,\s+x=\s*(.*?)?\)'
|
||||
# Match '#0 builtin_id(self=..., v=...)'
|
||||
r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)'
|
||||
# Match ' at Python/bltinmodule.c'.
|
||||
# bpo-38239: typing_idfunc() is defined in Module/_typingmldule.c,
|
||||
# bpo-38239: builtin_id() is defined in Python/bltinmodule.c,
|
||||
# but accept any "Directory\file.c" to support Link Time
|
||||
# Optimization (LTO).
|
||||
r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c',
|
||||
|
|
@ -50,13 +49,13 @@ def get_gdb_repr(self, source,
|
|||
return m.group(1), gdb_output
|
||||
|
||||
def test_getting_backtrace(self):
|
||||
gdb_output = self.get_stack_trace('from _typing import _idfunc;_idfunc(42)')
|
||||
gdb_output = self.get_stack_trace('id(42)')
|
||||
self.assertTrue(BREAKPOINT_FN in gdb_output)
|
||||
|
||||
def assertGdbRepr(self, val, exp_repr=None):
|
||||
# Ensure that gdb's rendering of the value in a debugged process
|
||||
# matches repr(value) in this process:
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('_idfunc(' + ascii(val) + ')')
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')')
|
||||
if not exp_repr:
|
||||
exp_repr = repr(val)
|
||||
self.assertEqual(gdb_repr, exp_repr,
|
||||
|
|
@ -174,7 +173,7 @@ def test_sets(self):
|
|||
# which happens on deletion:
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b'])
|
||||
s.remove('a')
|
||||
_idfunc(s)''')
|
||||
id(s)''')
|
||||
self.assertEqual(gdb_repr, "{'b'}")
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
|
|
@ -195,7 +194,7 @@ def test_exceptions(self):
|
|||
try:
|
||||
raise RuntimeError("I am an error")
|
||||
except RuntimeError as e:
|
||||
_idfunc(e)
|
||||
id(e)
|
||||
''')
|
||||
self.assertEqual(gdb_repr,
|
||||
"RuntimeError('I am an error',)")
|
||||
|
|
@ -206,7 +205,7 @@ def test_exceptions(self):
|
|||
try:
|
||||
a = 1 / 0
|
||||
except ZeroDivisionError as e:
|
||||
_idfunc(e)
|
||||
id(e)
|
||||
''')
|
||||
self.assertEqual(gdb_repr,
|
||||
"ZeroDivisionError('division by zero',)")
|
||||
|
|
@ -218,7 +217,7 @@ class Foo:
|
|||
pass
|
||||
foo = Foo()
|
||||
foo.an_int = 42
|
||||
_idfunc(foo)''')
|
||||
id(foo)''')
|
||||
m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr)
|
||||
self.assertTrue(m,
|
||||
msg='Unexpected new-style class rendering %r' % gdb_repr)
|
||||
|
|
@ -231,7 +230,7 @@ class Foo(list):
|
|||
foo = Foo()
|
||||
foo += [1, 2, 3]
|
||||
foo.an_int = 42
|
||||
_idfunc(foo)''')
|
||||
id(foo)''')
|
||||
m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr)
|
||||
|
||||
self.assertTrue(m,
|
||||
|
|
@ -246,7 +245,7 @@ class Foo(tuple):
|
|||
pass
|
||||
foo = Foo((1, 2, 3))
|
||||
foo.an_int = 42
|
||||
_idfunc(foo)''')
|
||||
id(foo)''')
|
||||
m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr)
|
||||
|
||||
self.assertTrue(m,
|
||||
|
|
@ -284,8 +283,8 @@ def assertSane(self, source, corruption, exprepr=None):
|
|||
def test_NULL_ptr(self):
|
||||
'Ensure that a NULL PyObject* is handled gracefully'
|
||||
gdb_repr, gdb_output = (
|
||||
self.get_gdb_repr('_idfunc(42)',
|
||||
cmds_after_breakpoint=['set variable x=0',
|
||||
self.get_gdb_repr('id(42)',
|
||||
cmds_after_breakpoint=['set variable v=0',
|
||||
'backtrace'])
|
||||
)
|
||||
|
||||
|
|
@ -293,25 +292,25 @@ def test_NULL_ptr(self):
|
|||
|
||||
def test_NULL_ob_type(self):
|
||||
'Ensure that a PyObject* with NULL ob_type is handled gracefully'
|
||||
self.assertSane('_idfunc(42)',
|
||||
'set x->ob_type=0')
|
||||
self.assertSane('id(42)',
|
||||
'set v->ob_type=0')
|
||||
|
||||
def test_corrupt_ob_type(self):
|
||||
'Ensure that a PyObject* with a corrupt ob_type is handled gracefully'
|
||||
self.assertSane('_idfunc(42)',
|
||||
'set x->ob_type=0xDEADBEEF',
|
||||
self.assertSane('id(42)',
|
||||
'set v->ob_type=0xDEADBEEF',
|
||||
exprepr='42')
|
||||
|
||||
def test_corrupt_tp_flags(self):
|
||||
'Ensure that a PyObject* with a type with corrupt tp_flags is handled'
|
||||
self.assertSane('_idfunc(42)',
|
||||
'set x->ob_type->tp_flags=0x0',
|
||||
self.assertSane('id(42)',
|
||||
'set v->ob_type->tp_flags=0x0',
|
||||
exprepr='42')
|
||||
|
||||
def test_corrupt_tp_name(self):
|
||||
'Ensure that a PyObject* with a type with corrupt tp_name is handled'
|
||||
self.assertSane('_idfunc(42)',
|
||||
'set x->ob_type->tp_name=0xDEADBEEF',
|
||||
self.assertSane('id(42)',
|
||||
'set v->ob_type->tp_name=0xDEADBEEF',
|
||||
exprepr='42')
|
||||
|
||||
def test_builtins_help(self):
|
||||
|
|
@ -322,7 +321,7 @@ def test_builtins_help(self):
|
|||
|
||||
# (this was the issue causing tracebacks in
|
||||
# http://bugs.python.org/issue8032#msg100537 )
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('_idfunc(__builtins__.help)', import_site=True)
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True)
|
||||
|
||||
m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr)
|
||||
self.assertTrue(m,
|
||||
|
|
@ -332,18 +331,18 @@ def test_selfreferential_list(self):
|
|||
'''Ensure that a reference loop involving a list doesn't lead proxyval
|
||||
into an infinite loop:'''
|
||||
gdb_repr, gdb_output = \
|
||||
self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; _idfunc(a)")
|
||||
self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; id(a)")
|
||||
self.assertEqual(gdb_repr, '[3, 4, 5, [...]]')
|
||||
|
||||
gdb_repr, gdb_output = \
|
||||
self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; _idfunc(a)")
|
||||
self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)")
|
||||
self.assertEqual(gdb_repr, '[3, 4, 5, [[...]]]')
|
||||
|
||||
def test_selfreferential_dict(self):
|
||||
'''Ensure that a reference loop involving a dict doesn't lead proxyval
|
||||
into an infinite loop:'''
|
||||
gdb_repr, gdb_output = \
|
||||
self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; _idfunc(a)")
|
||||
self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)")
|
||||
|
||||
self.assertEqual(gdb_repr, "{'foo': {'bar': {...}}}")
|
||||
|
||||
|
|
@ -354,7 +353,7 @@ class Foo:
|
|||
pass
|
||||
foo = Foo()
|
||||
foo.an_attr = foo
|
||||
_idfunc(foo)''')
|
||||
id(foo)''')
|
||||
self.assertTrue(re.match(r'<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>',
|
||||
gdb_repr),
|
||||
'Unexpected gdb representation: %r\n%s' % \
|
||||
|
|
@ -367,7 +366,7 @@ class Foo(object):
|
|||
pass
|
||||
foo = Foo()
|
||||
foo.an_attr = foo
|
||||
_idfunc(foo)''')
|
||||
id(foo)''')
|
||||
self.assertTrue(re.match(r'<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>',
|
||||
gdb_repr),
|
||||
'Unexpected gdb representation: %r\n%s' % \
|
||||
|
|
@ -381,7 +380,7 @@ class Foo(object):
|
|||
b = Foo()
|
||||
a.an_attr = b
|
||||
b.an_attr = a
|
||||
_idfunc(a)''')
|
||||
id(a)''')
|
||||
self.assertTrue(re.match(r'<Foo\(an_attr=<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>\) at remote 0x-?[0-9a-f]+>',
|
||||
gdb_repr),
|
||||
'Unexpected gdb representation: %r\n%s' % \
|
||||
|
|
@ -389,7 +388,7 @@ class Foo(object):
|
|||
|
||||
def test_truncation(self):
|
||||
'Verify that very long output is truncated'
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('_idfunc(list(range(1000)))')
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('id(list(range(1000)))')
|
||||
self.assertEqual(gdb_repr,
|
||||
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, "
|
||||
"14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, "
|
||||
|
|
@ -416,7 +415,7 @@ def test_truncation(self):
|
|||
1024 + len('...(truncated)'))
|
||||
|
||||
def test_builtin_method(self):
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('import sys; _idfunc(sys.stdout.readlines)')
|
||||
gdb_repr, gdb_output = self.get_gdb_repr('import sys; id(sys.stdout.readlines)')
|
||||
self.assertTrue(re.match(r'<built-in method readlines of _io.TextIOWrapper object at remote 0x-?[0-9a-f]+>',
|
||||
gdb_repr),
|
||||
'Unexpected gdb representation: %r\n%s' % \
|
||||
|
|
@ -425,16 +424,15 @@ def test_builtin_method(self):
|
|||
def test_frames(self):
|
||||
gdb_output = self.get_stack_trace('''
|
||||
import sys
|
||||
from _typing import _idfunc
|
||||
def foo(a, b, c):
|
||||
return sys._getframe(0)
|
||||
|
||||
f = foo(3, 4, 5)
|
||||
_idfunc(f)''',
|
||||
breakpoint='_typing__idfunc',
|
||||
cmds_after_breakpoint=['print (PyFrameObject*)x']
|
||||
id(f)''',
|
||||
breakpoint='builtin_id',
|
||||
cmds_after_breakpoint=['print (PyFrameObject*)v']
|
||||
)
|
||||
self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file <string>, line 5, in foo \(a=3.*',
|
||||
self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file <string>, line 4, in foo \(a=3.*',
|
||||
gdb_output,
|
||||
re.DOTALL),
|
||||
'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
'python-gdb.py')
|
||||
|
||||
SAMPLE_SCRIPT = os.path.join(os.path.dirname(__file__), 'gdb_sample.py')
|
||||
BREAKPOINT_FN = '_typing__idfunc'
|
||||
BREAKPOINT_FN = 'builtin_id'
|
||||
|
||||
PYTHONHASHSEED = '123'
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ def bar(x):
|
|||
p.stdin.write(user_input)
|
||||
user_input2 = dedent("""
|
||||
import linecache
|
||||
print(linecache._interactive_cache[id(foo.__code__)])
|
||||
print(linecache._interactive_cache[linecache._make_key(foo.__code__)])
|
||||
""")
|
||||
p.stdin.write(user_input2)
|
||||
output = kill_python(p)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue