mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
bpo-37499: Test various C calling conventions (GH-15776)
Add functions with various calling conventions to `_testcapi`, expose them as module-level functions, bound methods, class methods, and static methods, and test calling them and introspecting them through GDB. https://bugs.python.org/issue37499 Co-authored-by: Jeroen Demeyer <J.Demeyer@UGent.be> Automerge-Triggered-By: @pganssle
This commit is contained in:
parent
f1a297acb6
commit
f958377b67
3 changed files with 433 additions and 193 deletions
|
@ -838,47 +838,66 @@ id(42)
|
|||
)
|
||||
self.assertIn('Garbage-collecting', gdb_output)
|
||||
|
||||
|
||||
@unittest.skipIf(python_is_optimized(),
|
||||
"Python was compiled with optimizations")
|
||||
# Some older versions of gdb will fail with
|
||||
# "Cannot find new threads: generic error"
|
||||
# unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
|
||||
#
|
||||
# gdb will also generate many erroneous errors such as:
|
||||
# Function "meth_varargs" not defined.
|
||||
# This is because we are calling functions from an "external" module
|
||||
# (_testcapimodule) rather than compiled-in functions. It seems difficult
|
||||
# to suppress these. See also the comment in DebuggerTests.get_stack_trace
|
||||
def test_pycfunction(self):
|
||||
'Verify that "py-bt" displays invocations of PyCFunction instances'
|
||||
# Various optimizations multiply the code paths by which these are
|
||||
# called, so test a variety of calling conventions.
|
||||
for py_name, py_args, c_name, expected_frame_number in (
|
||||
('gmtime', '', 'time_gmtime', 1), # METH_VARARGS
|
||||
('len', '[]', 'builtin_len', 1), # METH_O
|
||||
('locals', '', 'builtin_locals', 1), # METH_NOARGS
|
||||
('iter', '[]', 'builtin_iter', 1), # METH_FASTCALL
|
||||
('sorted', '[]', 'builtin_sorted', 1), # METH_FASTCALL|METH_KEYWORDS
|
||||
for func_name, args, expected_frame in (
|
||||
('meth_varargs', '', 1),
|
||||
('meth_varargs_keywords', '', 1),
|
||||
('meth_o', '[]', 1),
|
||||
('meth_noargs', '', 1),
|
||||
('meth_fastcall', '', 1),
|
||||
('meth_fastcall_keywords', '', 1),
|
||||
):
|
||||
with self.subTest(c_name):
|
||||
cmd = ('from time import gmtime\n' # (not always needed)
|
||||
'def foo():\n'
|
||||
f' {py_name}({py_args})\n'
|
||||
'def bar():\n'
|
||||
' foo()\n'
|
||||
'bar()\n')
|
||||
# Verify with "py-bt":
|
||||
gdb_output = self.get_stack_trace(
|
||||
cmd,
|
||||
breakpoint=c_name,
|
||||
cmds_after_breakpoint=['bt', 'py-bt'],
|
||||
)
|
||||
self.assertIn(f'<built-in method {py_name}', gdb_output)
|
||||
for obj in (
|
||||
'_testcapi',
|
||||
'_testcapi.MethClass',
|
||||
'_testcapi.MethClass()',
|
||||
'_testcapi.MethStatic()',
|
||||
|
||||
# Verify with "py-bt-full":
|
||||
gdb_output = self.get_stack_trace(
|
||||
cmd,
|
||||
breakpoint=c_name,
|
||||
cmds_after_breakpoint=['py-bt-full'],
|
||||
)
|
||||
self.assertIn(
|
||||
f'#{expected_frame_number} <built-in method {py_name}',
|
||||
gdb_output,
|
||||
)
|
||||
# XXX: bound methods don't yet give nice tracebacks
|
||||
# '_testcapi.MethInstance()',
|
||||
):
|
||||
with self.subTest(f'{obj}.{func_name}'):
|
||||
cmd = textwrap.dedent(f'''
|
||||
import _testcapi
|
||||
def foo():
|
||||
{obj}.{func_name}({args})
|
||||
def bar():
|
||||
foo()
|
||||
bar()
|
||||
''')
|
||||
# Verify with "py-bt":
|
||||
gdb_output = self.get_stack_trace(
|
||||
cmd,
|
||||
breakpoint=func_name,
|
||||
cmds_after_breakpoint=['bt', 'py-bt'],
|
||||
)
|
||||
self.assertIn(f'<built-in method {func_name}', gdb_output)
|
||||
|
||||
# Verify with "py-bt-full":
|
||||
gdb_output = self.get_stack_trace(
|
||||
cmd,
|
||||
breakpoint=func_name,
|
||||
cmds_after_breakpoint=['py-bt-full'],
|
||||
)
|
||||
self.assertIn(
|
||||
f'#{expected_frame} <built-in method {func_name}',
|
||||
gdb_output,
|
||||
)
|
||||
|
||||
@unittest.skipIf(python_is_optimized(),
|
||||
"Python was compiled with optimizations")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue