| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  | import textwrap | 
					
						
							|  |  |  | import unittest | 
					
						
							|  |  |  | from test import support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .util import setup_module, DebuggerTests | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def setUpModule(): | 
					
						
							|  |  |  |     setup_module() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  | @unittest.skipIf(support.python_is_optimized(), | 
					
						
							| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  |                  "Python was compiled with optimizations") | 
					
						
							|  |  |  | @support.requires_resource('cpu') | 
					
						
							|  |  |  | class CFunctionTests(DebuggerTests): | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  |     def check(self, func_name, cmd): | 
					
						
							|  |  |  |         # 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  |     # 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 | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  |     def check_pycfunction(self, func_name, args): | 
					
						
							| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  |         'Verify that "py-bt" displays invocations of PyCFunction instances' | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if support.verbose: | 
					
						
							|  |  |  |             print() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  |         # Various optimizations multiply the code paths by which these are | 
					
						
							|  |  |  |         # called, so test a variety of calling conventions. | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  |         for obj in ( | 
					
						
							|  |  |  |             '_testcapi', | 
					
						
							|  |  |  |             '_testcapi.MethClass', | 
					
						
							|  |  |  |             '_testcapi.MethClass()', | 
					
						
							|  |  |  |             '_testcapi.MethStatic()', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # XXX: bound methods don't yet give nice tracebacks | 
					
						
							|  |  |  |             # '_testcapi.MethInstance()', | 
					
						
							| 
									
										
										
										
											2023-09-28 13:24:15 +02:00
										 |  |  |         ): | 
					
						
							| 
									
										
										
										
											2023-09-28 19:04:01 +02:00
										 |  |  |             with self.subTest(f'{obj}.{func_name}'): | 
					
						
							|  |  |  |                 call = f'{obj}.{func_name}({args})' | 
					
						
							|  |  |  |                 cmd = textwrap.dedent(f'''
 | 
					
						
							|  |  |  |                     import _testcapi | 
					
						
							|  |  |  |                     def foo(): | 
					
						
							|  |  |  |                         {call} | 
					
						
							|  |  |  |                     def bar(): | 
					
						
							|  |  |  |                         foo() | 
					
						
							|  |  |  |                     bar() | 
					
						
							|  |  |  |                 ''')
 | 
					
						
							|  |  |  |                 if support.verbose: | 
					
						
							|  |  |  |                     print(f'  test call: {call}', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 self.check(func_name, cmd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_noargs(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_noargs', '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_o(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_o', '[]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_varargs(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_varargs', '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_varargs_keywords(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_varargs_keywords', '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_fastcall(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_fastcall', '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pycfunction_fastcall_keywords(self): | 
					
						
							|  |  |  |         self.check_pycfunction('meth_fastcall_keywords', '') |