• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import textwrap
2import unittest
3from test import support
4
5from .util import setup_module, DebuggerTests
6
7
8def setUpModule():
9    setup_module()
10
11
12@unittest.skipIf(support.python_is_optimized(),
13                 "Python was compiled with optimizations")
14@support.requires_resource('cpu')
15class CFunctionTests(DebuggerTests):
16    def check(self, func_name, cmd):
17        # Verify with "py-bt":
18        gdb_output = self.get_stack_trace(
19            cmd,
20            breakpoint=func_name,
21            cmds_after_breakpoint=['bt', 'py-bt'],
22            # bpo-45207: Ignore 'Function "meth_varargs" not
23            # defined.' message in stderr.
24            ignore_stderr=True,
25        )
26        self.assertIn(f'<built-in method {func_name}', gdb_output)
27
28    # Some older versions of gdb will fail with
29    #  "Cannot find new threads: generic error"
30    # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
31    #
32    # gdb will also generate many erroneous errors such as:
33    #     Function "meth_varargs" not defined.
34    # This is because we are calling functions from an "external" module
35    # (_testcapimodule) rather than compiled-in functions. It seems difficult
36    # to suppress these. See also the comment in DebuggerTests.get_stack_trace
37    def check_pycfunction(self, func_name, args):
38        'Verify that "py-bt" displays invocations of PyCFunction instances'
39
40        if support.verbose:
41            print()
42
43        # Various optimizations multiply the code paths by which these are
44        # called, so test a variety of calling conventions.
45        for obj in (
46            '_testcapi',
47            '_testcapi.MethClass',
48            '_testcapi.MethClass()',
49            '_testcapi.MethStatic()',
50
51            # XXX: bound methods don't yet give nice tracebacks
52            # '_testcapi.MethInstance()',
53        ):
54            with self.subTest(f'{obj}.{func_name}'):
55                call = f'{obj}.{func_name}({args})'
56                cmd = textwrap.dedent(f'''
57                    import _testcapi
58                    def foo():
59                        {call}
60                    def bar():
61                        foo()
62                    bar()
63                ''')
64                if support.verbose:
65                    print(f'  test call: {call}', flush=True)
66
67                self.check(func_name, cmd)
68
69    def test_pycfunction_noargs(self):
70        self.check_pycfunction('meth_noargs', '')
71
72    def test_pycfunction_o(self):
73        self.check_pycfunction('meth_o', '[]')
74
75    def test_pycfunction_varargs(self):
76        self.check_pycfunction('meth_varargs', '')
77
78    def test_pycfunction_varargs_keywords(self):
79        self.check_pycfunction('meth_varargs_keywords', '')
80
81    def test_pycfunction_fastcall(self):
82        self.check_pycfunction('meth_fastcall', '')
83
84    def test_pycfunction_fastcall_keywords(self):
85        self.check_pycfunction('meth_fastcall_keywords', '')
86