summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_gdb/test_cfunction.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_gdb/test_cfunction.py')
-rw-r--r--Lib/test/test_gdb/test_cfunction.py83
1 files changed, 83 insertions, 0 deletions
diff --git a/Lib/test/test_gdb/test_cfunction.py b/Lib/test/test_gdb/test_cfunction.py
new file mode 100644
index 0000000..55796d0
--- /dev/null
+++ b/Lib/test/test_gdb/test_cfunction.py
@@ -0,0 +1,83 @@
+import re
+import textwrap
+import unittest
+from test import support
+from test.support import python_is_optimized
+
+from .util import setup_module, DebuggerTests
+
+
+def setUpModule():
+ setup_module()
+
+
+@unittest.skipIf(python_is_optimized(),
+ "Python was compiled with optimizations")
+@support.requires_resource('cpu')
+class CFunctionTests(DebuggerTests):
+ # 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'
+ # bpo-46600: If the compiler inlines _null_to_none() in meth_varargs()
+ # (ex: clang -Og), _null_to_none() is the frame #1. Otherwise,
+ # meth_varargs() is the frame #1.
+ expected_frame = r'#(1|2)'
+ # Various optimizations multiply the code paths by which these are
+ # called, so test a variety of calling conventions.
+ for func_name, args in (
+ ('meth_varargs', ''),
+ ('meth_varargs_keywords', ''),
+ ('meth_o', '[]'),
+ ('meth_noargs', ''),
+ ('meth_fastcall', ''),
+ ('meth_fastcall_keywords', ''),
+ ):
+ for obj in (
+ '_testcapi',
+ '_testcapi.MethClass',
+ '_testcapi.MethClass()',
+ '_testcapi.MethStatic()',
+
+ # 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'],
+ # bpo-45207: Ignore 'Function "meth_varargs" not
+ # defined.' message in stderr.
+ ignore_stderr=True,
+ )
+ 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'],
+ # bpo-45207: Ignore 'Function "meth_varargs" not
+ # defined.' message in stderr.
+ ignore_stderr=True,
+ )
+ regex = expected_frame
+ regex += re.escape(f' <built-in method {func_name}')
+ self.assertRegex(gdb_output, regex)