blob: b81b34d3ef0f49027dd76440cf6514c395997842 [file] [log] [blame]
Victor Stinner024e37a2011-03-31 01:31:06 +02001from contextlib import contextmanager
Victor Stinnerc790a532011-04-08 13:39:59 +02002import datetime
Victor Stinner024e37a2011-03-31 01:31:06 +02003import faulthandler
Victor Stinner7e32f3a2011-06-29 13:44:05 +02004import os
Victor Stinner024e37a2011-03-31 01:31:06 +02005import re
6import signal
7import subprocess
8import sys
9from test import support, script_helper
Victor Stinnerd5698cb2012-07-31 02:55:49 +020010from test.script_helper import assert_python_ok
Victor Stinner024e37a2011-03-31 01:31:06 +020011import tempfile
12import unittest
13
Victor Stinnerff4cd882011-04-07 11:50:25 +020014try:
15 import threading
16 HAVE_THREADS = True
17except ImportError:
18 HAVE_THREADS = False
19
Victor Stinner44378d42011-04-01 15:37:12 +020020TIMEOUT = 0.5
21
Victor Stinner024e37a2011-03-31 01:31:06 +020022try:
23 from resource import setrlimit, RLIMIT_CORE, error as resource_error
24except ImportError:
25 prepare_subprocess = None
26else:
27 def prepare_subprocess():
28 # don't create core file
29 try:
30 setrlimit(RLIMIT_CORE, (0, 0))
31 except (ValueError, resource_error):
32 pass
33
Victor Stinner301f3f02011-06-01 13:49:12 +020034def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020035 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020036 regex += ' File "<string>", line %s in func\n' % lineno1
37 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020038 if 1 < min_count:
39 return '^' + (regex + '\n') * (min_count - 1) + regex
40 else:
41 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020042
43@contextmanager
44def temporary_filename():
45 filename = tempfile.mktemp()
46 try:
47 yield filename
48 finally:
49 support.unlink(filename)
50
51class FaultHandlerTests(unittest.TestCase):
Victor Stinner05585cb2011-03-31 13:29:56 +020052 def get_output(self, code, filename=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020053 """
54 Run the specified code in Python (in a new child process) and read the
55 output from the standard error or from a file (if filename is set).
56 Return the output lines as a list.
57
58 Strip the reference count from the standard error for Python debug
59 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
60 thread XXX".
61 """
62 options = {}
63 if prepare_subprocess:
64 options['preexec_fn'] = prepare_subprocess
65 process = script_helper.spawn_python('-c', code, **options)
66 stdout, stderr = process.communicate()
67 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020068 output = support.strip_python_stderr(stdout)
69 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020070 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020071 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020072 with open(filename, "rb") as fp:
73 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020074 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020075 output = re.sub('Current thread 0x[0-9a-f]+',
76 'Current thread XXX',
77 output)
Victor Stinner05585cb2011-03-31 13:29:56 +020078 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020079
80 def check_fatal_error(self, code, line_number, name_regex,
Victor Stinner7bba62f2011-05-07 12:43:00 +020081 filename=None, all_threads=True, other_regex=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020082 """
83 Check that the fault handler for fatal errors is enabled and check the
84 traceback from the child process output.
85
86 Raise an error if the output doesn't match the expected format.
87 """
88 if all_threads:
89 header = 'Current thread XXX'
90 else:
91 header = 'Traceback (most recent call first)'
92 regex = """
93^Fatal Python error: {name}
94
95{header}:
Vinay Sajip36371232012-05-06 11:28:46 +010096 File "<string>", line {lineno} in <module>
Victor Stinner024e37a2011-03-31 01:31:06 +020097""".strip()
98 regex = regex.format(
99 lineno=line_number,
100 name=name_regex,
101 header=re.escape(header))
Victor Stinnerf0480752011-03-31 11:34:08 +0200102 if other_regex:
103 regex += '|' + other_regex
Victor Stinner05585cb2011-03-31 13:29:56 +0200104 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200105 output = '\n'.join(output)
106 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200107 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200108
109 def test_read_null(self):
110 self.check_fatal_error("""
111import faulthandler
112faulthandler.enable()
113faulthandler._read_null()
114""".strip(),
115 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200116 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
117 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200118
119 def test_sigsegv(self):
120 self.check_fatal_error("""
121import faulthandler
122faulthandler.enable()
123faulthandler._sigsegv()
124""".strip(),
125 3,
126 'Segmentation fault')
127
Victor Stinnerd727e232011-04-01 12:13:55 +0200128 def test_sigabrt(self):
129 self.check_fatal_error("""
130import faulthandler
131faulthandler.enable()
132faulthandler._sigabrt()
133""".strip(),
134 3,
135 'Aborted')
136
Victor Stinner024e37a2011-03-31 01:31:06 +0200137 @unittest.skipIf(sys.platform == 'win32',
138 "SIGFPE cannot be caught on Windows")
139 def test_sigfpe(self):
140 self.check_fatal_error("""
141import faulthandler
142faulthandler.enable()
143faulthandler._sigfpe()
144""".strip(),
145 3,
146 'Floating point exception')
147
148 @unittest.skipIf(not hasattr(faulthandler, '_sigbus'),
149 "need faulthandler._sigbus()")
150 def test_sigbus(self):
151 self.check_fatal_error("""
152import faulthandler
153faulthandler.enable()
154faulthandler._sigbus()
155""".strip(),
156 3,
157 'Bus error')
158
159 @unittest.skipIf(not hasattr(faulthandler, '_sigill'),
160 "need faulthandler._sigill()")
161 def test_sigill(self):
162 self.check_fatal_error("""
163import faulthandler
164faulthandler.enable()
165faulthandler._sigill()
166""".strip(),
167 3,
168 'Illegal instruction')
169
170 def test_fatal_error(self):
171 self.check_fatal_error("""
172import faulthandler
173faulthandler._fatal_error(b'xyz')
174""".strip(),
175 2,
176 'xyz')
177
Charles-François Natali3391e642011-09-01 23:08:21 +0200178 @unittest.skipIf(sys.platform.startswith('openbsd') and HAVE_THREADS,
179 "Issue #12868: sigaltstack() doesn't work on "
180 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200181 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
182 'need faulthandler._stack_overflow()')
183 def test_stack_overflow(self):
184 self.check_fatal_error("""
185import faulthandler
186faulthandler.enable()
187faulthandler._stack_overflow()
188""".strip(),
189 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200190 '(?:Segmentation fault|Bus error)',
191 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200192
193 def test_gil_released(self):
194 self.check_fatal_error("""
195import faulthandler
196faulthandler.enable()
197faulthandler._read_null(True)
198""".strip(),
199 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200200 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200201
202 def test_enable_file(self):
203 with temporary_filename() as filename:
204 self.check_fatal_error("""
205import faulthandler
206output = open({filename}, 'wb')
207faulthandler.enable(output)
Victor Stinner44378d42011-04-01 15:37:12 +0200208faulthandler._read_null()
Victor Stinner024e37a2011-03-31 01:31:06 +0200209""".strip().format(filename=repr(filename)),
210 4,
Victor Stinnera8db3782011-08-08 22:43:45 +0200211 '(?:Segmentation fault|Bus error|Illegal instruction)',
Victor Stinner024e37a2011-03-31 01:31:06 +0200212 filename=filename)
213
Victor Stinner7bba62f2011-05-07 12:43:00 +0200214 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200215 self.check_fatal_error("""
216import faulthandler
Victor Stinner7bba62f2011-05-07 12:43:00 +0200217faulthandler.enable(all_threads=False)
Victor Stinner44378d42011-04-01 15:37:12 +0200218faulthandler._read_null()
Victor Stinner024e37a2011-03-31 01:31:06 +0200219""".strip(),
220 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200221 '(?:Segmentation fault|Bus error|Illegal instruction)',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200222 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200223
224 def test_disable(self):
225 code = """
226import faulthandler
227faulthandler.enable()
228faulthandler.disable()
229faulthandler._read_null()
230""".strip()
231 not_expected = 'Fatal Python error'
Victor Stinner05585cb2011-03-31 13:29:56 +0200232 stderr, exitcode = self.get_output(code)
Victor Stinner024e37a2011-03-31 01:31:06 +0200233 stder = '\n'.join(stderr)
234 self.assertTrue(not_expected not in stderr,
235 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200236 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200237
238 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200239 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200240 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200241 # regrtest may replace sys.stderr by io.StringIO object, but
242 # faulthandler.enable() requires that sys.stderr has a fileno()
243 # method
Victor Stinner72488502011-06-29 23:24:31 +0200244 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200245
246 was_enabled = faulthandler.is_enabled()
247 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200248 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200249 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200250 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200251 self.assertFalse(faulthandler.is_enabled())
252 finally:
253 if was_enabled:
254 faulthandler.enable()
255 else:
256 faulthandler.disable()
257 finally:
258 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200259
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200260 def test_disabled_by_default(self):
261 # By default, the module should be disabled
262 code = "import faulthandler; print(faulthandler.is_enabled())"
263 rc, stdout, stderr = assert_python_ok("-c", code)
264 stdout = (stdout + stderr).strip()
265 self.assertEqual(stdout, b"False")
266
267 def test_sys_xoptions(self):
268 # Test python -X faulthandler
269 code = "import faulthandler; print(faulthandler.is_enabled())"
270 rc, stdout, stderr = assert_python_ok("-X", "faulthandler", "-c", code)
271 stdout = (stdout + stderr).strip()
272 self.assertEqual(stdout, b"True")
273
Victor Stinner024e37a2011-03-31 01:31:06 +0200274 def check_dump_traceback(self, filename):
275 """
276 Explicitly call dump_traceback() function and check its output.
277 Raise an error if the output doesn't match the expected format.
278 """
279 code = """
280import faulthandler
281
282def funcB():
283 if {has_filename}:
284 with open({filename}, "wb") as fp:
Victor Stinner7bba62f2011-05-07 12:43:00 +0200285 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200286 else:
Victor Stinner7bba62f2011-05-07 12:43:00 +0200287 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200288
289def funcA():
290 funcB()
291
292funcA()
293""".strip()
294 code = code.format(
295 filename=repr(filename),
296 has_filename=bool(filename),
297 )
298 if filename:
299 lineno = 6
300 else:
301 lineno = 8
302 expected = [
303 'Traceback (most recent call first):',
304 ' File "<string>", line %s in funcB' % lineno,
305 ' File "<string>", line 11 in funcA',
306 ' File "<string>", line 13 in <module>'
307 ]
Victor Stinner05585cb2011-03-31 13:29:56 +0200308 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200310 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200311
312 def test_dump_traceback(self):
313 self.check_dump_traceback(None)
Victor Stinner19402332011-03-31 18:15:52 +0200314
315 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200316 with temporary_filename() as filename:
317 self.check_dump_traceback(filename)
318
Victor Stinner53386d82012-08-01 19:45:34 +0200319 def test_truncate(self):
320 maxlen = 500
321 func_name = 'x' * (maxlen + 50)
322 truncated = 'x' * maxlen + '...'
323 code = """
324import faulthandler
325
326def {func_name}():
327 faulthandler.dump_traceback(all_threads=False)
328
329{func_name}()
330""".strip()
331 code = code.format(
332 func_name=func_name,
333 )
334 expected = [
335 'Traceback (most recent call first):',
336 ' File "<string>", line 4 in %s' % truncated,
337 ' File "<string>", line 6 in <module>'
338 ]
339 trace, exitcode = self.get_output(code)
340 self.assertEqual(trace, expected)
341 self.assertEqual(exitcode, 0)
342
Victor Stinnerff4cd882011-04-07 11:50:25 +0200343 @unittest.skipIf(not HAVE_THREADS, 'need threads')
Victor Stinner024e37a2011-03-31 01:31:06 +0200344 def check_dump_traceback_threads(self, filename):
345 """
346 Call explicitly dump_traceback(all_threads=True) and check the output.
347 Raise an error if the output doesn't match the expected format.
348 """
349 code = """
350import faulthandler
351from threading import Thread, Event
352import time
353
354def dump():
355 if {filename}:
356 with open({filename}, "wb") as fp:
357 faulthandler.dump_traceback(fp, all_threads=True)
358 else:
359 faulthandler.dump_traceback(all_threads=True)
360
361class Waiter(Thread):
362 # avoid blocking if the main thread raises an exception.
363 daemon = True
364
365 def __init__(self):
366 Thread.__init__(self)
367 self.running = Event()
368 self.stop = Event()
369
370 def run(self):
371 self.running.set()
372 self.stop.wait()
373
374waiter = Waiter()
375waiter.start()
376waiter.running.wait()
377dump()
378waiter.stop.set()
379waiter.join()
380""".strip()
381 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200382 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200383 output = '\n'.join(output)
384 if filename:
385 lineno = 8
386 else:
387 lineno = 10
388 regex = """
389^Thread 0x[0-9a-f]+:
Victor Stinner1b3241f2011-04-03 18:41:22 +0200390(?: File ".*threading.py", line [0-9]+ in [_a-z]+
391){{1,3}} File "<string>", line 23 in run
Victor Stinner024e37a2011-03-31 01:31:06 +0200392 File ".*threading.py", line [0-9]+ in _bootstrap_inner
393 File ".*threading.py", line [0-9]+ in _bootstrap
394
395Current thread XXX:
396 File "<string>", line {lineno} in dump
397 File "<string>", line 28 in <module>$
398""".strip()
399 regex = regex.format(lineno=lineno)
400 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200401 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200402
403 def test_dump_traceback_threads(self):
404 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200405
406 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200407 with temporary_filename() as filename:
408 self.check_dump_traceback_threads(filename)
409
Georg Brandldeb92b52012-09-22 08:58:55 +0200410 def _check_dump_traceback_later(self, repeat, cancel, filename, loops):
Victor Stinner024e37a2011-03-31 01:31:06 +0200411 """
412 Check how many times the traceback is written in timeout x 2.5 seconds,
413 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
414 on repeat and cancel options.
415
416 Raise an error if the output doesn't match the expect format.
417 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200418 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200419 code = """
420import faulthandler
421import time
422
Victor Stinnerde10f402011-04-08 12:57:06 +0200423def func(timeout, repeat, cancel, file, loops):
424 for loop in range(loops):
Georg Brandldeb92b52012-09-22 08:58:55 +0200425 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
Victor Stinnerde10f402011-04-08 12:57:06 +0200426 if cancel:
Georg Brandldeb92b52012-09-22 08:58:55 +0200427 faulthandler.cancel_dump_traceback_later()
Victor Stinner301f3f02011-06-01 13:49:12 +0200428 time.sleep(timeout * 5)
Georg Brandldeb92b52012-09-22 08:58:55 +0200429 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200430
Victor Stinner44378d42011-04-01 15:37:12 +0200431timeout = {timeout}
Victor Stinner024e37a2011-03-31 01:31:06 +0200432repeat = {repeat}
433cancel = {cancel}
Victor Stinnerde10f402011-04-08 12:57:06 +0200434loops = {loops}
Victor Stinner024e37a2011-03-31 01:31:06 +0200435if {has_filename}:
436 file = open({filename}, "wb")
437else:
438 file = None
Victor Stinnerde10f402011-04-08 12:57:06 +0200439func(timeout, repeat, cancel, file, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200440if file is not None:
441 file.close()
442""".strip()
443 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200444 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200445 repeat=repeat,
446 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200447 loops=loops,
448 has_filename=bool(filename),
449 filename=repr(filename),
Victor Stinner024e37a2011-03-31 01:31:06 +0200450 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200451 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200452 trace = '\n'.join(trace)
453
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200454 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200455 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200456 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200457 count *= 2
Victor Stinnerc790a532011-04-08 13:39:59 +0200458 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+:\n' % timeout_str
Victor Stinner301f3f02011-06-01 13:49:12 +0200459 regex = expected_traceback(9, 20, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200460 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200461 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200462 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200463 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200464
Georg Brandldeb92b52012-09-22 08:58:55 +0200465 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
466 'need faulthandler.dump_traceback_later()')
467 def check_dump_traceback_later(self, repeat=False, cancel=False,
Victor Stinnerde10f402011-04-08 12:57:06 +0200468 file=False, twice=False):
469 if twice:
470 loops = 2
471 else:
472 loops = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200473 if file:
474 with temporary_filename() as filename:
Georg Brandldeb92b52012-09-22 08:58:55 +0200475 self._check_dump_traceback_later(repeat, cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200476 filename, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200477 else:
Georg Brandldeb92b52012-09-22 08:58:55 +0200478 self._check_dump_traceback_later(repeat, cancel, None, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200479
Georg Brandldeb92b52012-09-22 08:58:55 +0200480 def test_dump_traceback_later(self):
481 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200482
Georg Brandldeb92b52012-09-22 08:58:55 +0200483 def test_dump_traceback_later_repeat(self):
484 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200485
Georg Brandldeb92b52012-09-22 08:58:55 +0200486 def test_dump_traceback_later_cancel(self):
487 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200488
Georg Brandldeb92b52012-09-22 08:58:55 +0200489 def test_dump_traceback_later_file(self):
490 self.check_dump_traceback_later(file=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200491
Georg Brandldeb92b52012-09-22 08:58:55 +0200492 def test_dump_traceback_later_twice(self):
493 self.check_dump_traceback_later(twice=True)
Victor Stinnerde10f402011-04-08 12:57:06 +0200494
Victor Stinner024e37a2011-03-31 01:31:06 +0200495 @unittest.skipIf(not hasattr(faulthandler, "register"),
496 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200497 def check_register(self, filename=False, all_threads=False,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200498 unregister=False, chain=False):
Victor Stinner024e37a2011-03-31 01:31:06 +0200499 """
500 Register a handler displaying the traceback on a user signal. Raise the
501 signal and check the written traceback.
502
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200503 If chain is True, check that the previous signal handler is called.
504
Victor Stinner024e37a2011-03-31 01:31:06 +0200505 Raise an error if the output doesn't match the expected format.
506 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200507 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200508 code = """
509import faulthandler
510import os
511import signal
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200512import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200513
514def func(signum):
515 os.kill(os.getpid(), signum)
516
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200517def handler(signum, frame):
518 handler.called = True
519handler.called = False
520
521exitcode = 0
Victor Stinnera01ca122011-04-01 12:56:17 +0200522signum = {signum}
523unregister = {unregister}
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200524chain = {chain}
525
Victor Stinner024e37a2011-03-31 01:31:06 +0200526if {has_filename}:
527 file = open({filename}, "wb")
528else:
529 file = None
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200530if chain:
531 signal.signal(signum, handler)
532faulthandler.register(signum, file=file,
533 all_threads={all_threads}, chain={chain})
Victor Stinnera01ca122011-04-01 12:56:17 +0200534if unregister:
535 faulthandler.unregister(signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200536func(signum)
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200537if chain and not handler.called:
538 if file is not None:
539 output = file
540 else:
541 output = sys.stderr
542 print("Error: signal handler not called!", file=output)
543 exitcode = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200544if file is not None:
545 file.close()
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200546sys.exit(exitcode)
Victor Stinner024e37a2011-03-31 01:31:06 +0200547""".strip()
548 code = code.format(
549 filename=repr(filename),
550 has_filename=bool(filename),
551 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200552 signum=signum,
553 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200554 chain=chain,
Victor Stinner024e37a2011-03-31 01:31:06 +0200555 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200556 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200557 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200558 if not unregister:
559 if all_threads:
560 regex = 'Current thread XXX:\n'
561 else:
562 regex = 'Traceback \(most recent call first\):\n'
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200563 regex = expected_traceback(7, 28, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200564 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200565 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200566 self.assertEqual(trace, '')
567 if unregister:
568 self.assertNotEqual(exitcode, 0)
569 else:
570 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200571
572 def test_register(self):
573 self.check_register()
574
Victor Stinnera01ca122011-04-01 12:56:17 +0200575 def test_unregister(self):
576 self.check_register(unregister=True)
577
Victor Stinner024e37a2011-03-31 01:31:06 +0200578 def test_register_file(self):
579 with temporary_filename() as filename:
580 self.check_register(filename=filename)
581
582 def test_register_threads(self):
583 self.check_register(all_threads=True)
584
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200585 def test_register_chain(self):
586 self.check_register(chain=True)
587
Victor Stinner024e37a2011-03-31 01:31:06 +0200588
589def test_main():
590 support.run_unittest(FaultHandlerTests)
591
592if __name__ == "__main__":
593 test_main()