2727MS_WINDOWS = (os .name == 'nt' )
2828
2929
30- def expected_traceback (lineno1 , lineno2 , header , min_count = 1 ):
30+ def expected_traceback (lineno1 , lineno2 , header , min_count = 1 , * , c_call_stack = True ):
3131 regex = header
3232 regex += ' File "<string>", line %s in func\n ' % lineno1
3333 regex += ' File "<string>", line %s in <module>' % lineno2
3434 if 1 < min_count :
35+ assert not c_call_stack
3536 return '^' + (regex + '\n ' ) * (min_count - 1 ) + regex
3637 else :
37- return '^' + regex + '$'
38+ if c_call_stack :
39+ return '^' + regex + "\n \n Current thread's C call stack"
40+ else :
41+ return '^' + regex + '$'
3842
3943def skip_segfault_on_android (test ):
4044 # Issue #32138: Raising SIGSEGV on Android may not cause a crash.
@@ -89,6 +93,7 @@ def check_error(self, code, lineno, fatal_error, *,
8993 fd = None , know_current_thread = True ,
9094 py_fatal_error = False ,
9195 garbage_collecting = False ,
96+ c_call_stack = True ,
9297 function = '<module>' ):
9398 """
9499 Check that the fault handler for fatal errors is enabled and check the
@@ -110,7 +115,19 @@ def check_error(self, code, lineno, fatal_error, *,
110115 regex .append (fr'{ header } \(most recent call first\):' )
111116 if garbage_collecting :
112117 regex .append (' Garbage-collecting' )
113- regex .append (fr' File "<string>", line { lineno } in { function } ' )
118+ regex .append (
119+ fr' File "<string>", line { lineno } in { function } '
120+ r'(?:\n File "<string>", line \d+ in .*)*'
121+ )
122+ if c_call_stack :
123+ regex .append ('' )
124+ regex .append (r"Current thread's C call stack \(most recent call first\):" )
125+ regex .append (
126+ # First line should always be in the cfaulthandler shared library
127+ fr"{ re .escape (cfaulthandler .__file__ )} \(.*\+0x[0-9a-f]+\)\[0x[0-9a-f]+\]"
128+ # Remaining lines could be anywhere
129+ r"(?:\n.*(?:\(.*\+0x[0-9a-f]+\))?\[0x[0-9a-f]+\])+"
130+ )
114131 regex = '\n ' .join (regex )
115132
116133 if other_regex :
@@ -212,7 +229,8 @@ def test_fatal_error_c_thread(self):
212229 'in new thread' ,
213230 know_current_thread = False ,
214231 func = 'cfaulthandler_fatal_error_thread' ,
215- py_fatal_error = True )
232+ py_fatal_error = True ,
233+ c_call_stack = False )
216234
217235 def test_sigabrt (self ):
218236 self .check_fatal_error ("""
@@ -272,7 +290,8 @@ def check_fatal_error_func(self, release_gil):
272290 2 ,
273291 'xyz' ,
274292 func = 'test_fatal_error' ,
275- py_fatal_error = True )
293+ py_fatal_error = True ,
294+ c_call_stack = False )
276295
277296 def test_fatal_error (self ):
278297 self .check_fatal_error_func (False )
@@ -451,14 +470,17 @@ def funcA():
451470 lineno = 11
452471 else :
453472 lineno = 14
454- expected = [
473+ expected_start = [
455474 'Stack (most recent call first):' ,
456475 ' File "<string>", line %s in funcB' % lineno ,
457476 ' File "<string>", line 17 in funcA' ,
458- ' File "<string>", line 19 in <module>'
477+ ' File "<string>", line 19 in <module>' ,
478+ '' ,
479+ "Current thread's C call stack (most recent call first):" ,
459480 ]
460481 trace , exitcode = self .get_output (code , filename , fd )
461- self .assertEqual (trace , expected )
482+ self .assertEqual (trace [:len (expected_start )], expected_start )
483+ self .assertRegex (trace [len (expected_start )], fr"{ re .escape (cfaulthandler .__file__ )} \(.*\+0x[0-9a-f]+\)\[0x[0-9a-f]+\]" )
462484 self .assertEqual (exitcode , 0 )
463485
464486 def test_dump_traceback (self ):
@@ -495,7 +517,7 @@ def {func_name}():
495517 ' File "<string>", line 6 in <module>'
496518 ]
497519 trace , exitcode = self .get_output (code )
498- self .assertEqual (trace , expected )
520+ self .assertEqual (trace [: len ( expected )] , expected )
499521 self .assertEqual (exitcode , 0 )
500522
501523 def check_dump_traceback_threads (self , filename ):
@@ -551,7 +573,9 @@ def run(self):
551573
552574 Current thread 0x[0-9a-f]+ \(most recent call first\):
553575 File "<string>", line {lineno} in dump
554- File "<string>", line 28 in <module>$
576+ File "<string>", line 28 in <module>
577+
578+ Current thread's C call stack \(most recent call first\):
555579 """
556580 regex = dedent (regex .format (lineno = lineno )).strip ()
557581 self .assertRegex (output , regex )
@@ -620,7 +644,7 @@ def func(timeout, repeat, cancel, file, loops):
620644 if repeat :
621645 count *= 2
622646 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
623- regex = expected_traceback (17 , 26 , header , min_count = count )
647+ regex = expected_traceback (17 , 26 , header , min_count = count , c_call_stack = False )
624648 self .assertRegex (trace , regex )
625649 else :
626650 self .assertEqual (trace , '' )
0 commit comments