summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_gdb/test_cfunction.py
blob: 55796d021511e198f6a04d4bc8d0686f0fd8387f (plain)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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)