summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2019-06-02 21:11:24 (GMT)
committerGitHub <noreply@github.com>2019-06-02 21:11:24 (GMT)
commit64e2c64f7f0111c52834155becc0c6134f9d8750 (patch)
tree492201b477926f0b1a4eea7425c771518a63757a
parentcdce0574d03005e27b843fc110c54c99c7a76412 (diff)
downloadcpython-64e2c64f7f0111c52834155becc0c6134f9d8750.zip
cpython-64e2c64f7f0111c52834155becc0c6134f9d8750.tar.gz
cpython-64e2c64f7f0111c52834155becc0c6134f9d8750.tar.bz2
test_gdb.test_pycfunction: test more calling conventions (GH-13668)
As the code paths for various METH_* conventions are diverging due to optimizations, we should check they continue to be covered by GDB integration.
-rw-r--r--Lib/test/test_gdb.py55
1 files changed, 34 insertions, 21 deletions
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index 3127e69..f57e348 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -867,27 +867,40 @@ id(42)
# unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
def test_pycfunction(self):
'Verify that "py-bt" displays invocations of PyCFunction instances'
- # Tested function must not be defined with METH_NOARGS or METH_O,
- # otherwise call_function() doesn't call PyCFunction_Call()
- cmd = ('from time import gmtime\n'
- 'def foo():\n'
- ' gmtime(1)\n'
- 'def bar():\n'
- ' foo()\n'
- 'bar()\n')
- # Verify with "py-bt":
- gdb_output = self.get_stack_trace(cmd,
- breakpoint='time_gmtime',
- cmds_after_breakpoint=['bt', 'py-bt'],
- )
- self.assertIn('<built-in method gmtime', gdb_output)
-
- # Verify with "py-bt-full":
- gdb_output = self.get_stack_trace(cmd,
- breakpoint='time_gmtime',
- cmds_after_breakpoint=['py-bt-full'],
- )
- self.assertIn('#1 <built-in method gmtime', gdb_output)
+ # 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', 2), # METH_O
+ ('locals', '', 'builtin_locals', 2), # METH_NOARGS
+ ('iter', '[]', 'builtin_iter', 2), # METH_FASTCALL
+ ('sorted', '[]', 'builtin_sorted', 2), # METH_FASTCALL|METH_KEYWORDS
+ ):
+ 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)
+
+ # 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,
+ )
@unittest.skipIf(python_is_optimized(),
"Python was compiled with optimizations")