blob: 8dcefe41aed25cbac03cc36db0512addbed88b48 [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
Victor Stinner6d201682014-08-10 19:50:08 +020013from textwrap import dedent
Victor Stinner024e37a2011-03-31 01:31:06 +020014
Victor Stinnerff4cd882011-04-07 11:50:25 +020015try:
16 import threading
17 HAVE_THREADS = True
18except ImportError:
19 HAVE_THREADS = False
20
Victor Stinner44378d42011-04-01 15:37:12 +020021TIMEOUT = 0.5
22
Victor Stinner301f3f02011-06-01 13:49:12 +020023def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020024 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020025 regex += ' File "<string>", line %s in func\n' % lineno1
26 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020027 if 1 < min_count:
28 return '^' + (regex + '\n') * (min_count - 1) + regex
29 else:
30 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020031
32@contextmanager
33def temporary_filename():
34 filename = tempfile.mktemp()
35 try:
36 yield filename
37 finally:
38 support.unlink(filename)
39
40class FaultHandlerTests(unittest.TestCase):
Victor Stinner05585cb2011-03-31 13:29:56 +020041 def get_output(self, code, filename=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020042 """
43 Run the specified code in Python (in a new child process) and read the
44 output from the standard error or from a file (if filename is set).
45 Return the output lines as a list.
46
47 Strip the reference count from the standard error for Python debug
48 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
49 thread XXX".
50 """
Victor Stinner6d201682014-08-10 19:50:08 +020051 code = dedent(code).strip()
Antoine Pitrou77e904e2013-10-08 23:04:32 +020052 with support.SuppressCrashReport():
53 process = script_helper.spawn_python('-c', code)
Victor Stinner024e37a2011-03-31 01:31:06 +020054 stdout, stderr = process.communicate()
55 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020056 output = support.strip_python_stderr(stdout)
57 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020058 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020059 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020060 with open(filename, "rb") as fp:
61 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020062 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020063 output = re.sub('Current thread 0x[0-9a-f]+',
64 'Current thread XXX',
65 output)
Victor Stinner05585cb2011-03-31 13:29:56 +020066 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020067
68 def check_fatal_error(self, code, line_number, name_regex,
Victor Stinner7bba62f2011-05-07 12:43:00 +020069 filename=None, all_threads=True, other_regex=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020070 """
71 Check that the fault handler for fatal errors is enabled and check the
72 traceback from the child process output.
73
74 Raise an error if the output doesn't match the expected format.
75 """
76 if all_threads:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -070077 header = 'Current thread XXX (most recent call first)'
Victor Stinner024e37a2011-03-31 01:31:06 +020078 else:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -070079 header = 'Stack (most recent call first)'
Victor Stinner024e37a2011-03-31 01:31:06 +020080 regex = """
Victor Stinner6d201682014-08-10 19:50:08 +020081 ^Fatal Python error: {name}
Victor Stinner024e37a2011-03-31 01:31:06 +020082
Victor Stinner6d201682014-08-10 19:50:08 +020083 {header}:
84 File "<string>", line {lineno} in <module>
85 """
86 regex = dedent(regex.format(
Victor Stinner024e37a2011-03-31 01:31:06 +020087 lineno=line_number,
88 name=name_regex,
Victor Stinner6d201682014-08-10 19:50:08 +020089 header=re.escape(header))).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +020090 if other_regex:
91 regex += '|' + other_regex
Antoine Pitrou77e904e2013-10-08 23:04:32 +020092 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +020093 output = '\n'.join(output)
94 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +020095 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +020096
Victor Stinner330426c2013-07-03 22:29:42 +020097 @unittest.skipIf(sys.platform.startswith('aix'),
98 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +020099 def test_read_null(self):
100 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200101 import faulthandler
102 faulthandler.enable()
103 faulthandler._read_null()
104 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200105 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200106 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
107 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200108
109 def test_sigsegv(self):
110 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200111 import faulthandler
112 faulthandler.enable()
113 faulthandler._sigsegv()
114 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200115 3,
116 'Segmentation fault')
117
Victor Stinnerd727e232011-04-01 12:13:55 +0200118 def test_sigabrt(self):
119 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200120 import faulthandler
121 faulthandler.enable()
122 faulthandler._sigabrt()
123 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200124 3,
125 'Aborted')
126
Victor Stinner024e37a2011-03-31 01:31:06 +0200127 @unittest.skipIf(sys.platform == 'win32',
128 "SIGFPE cannot be caught on Windows")
129 def test_sigfpe(self):
130 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200131 import faulthandler
132 faulthandler.enable()
133 faulthandler._sigfpe()
134 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200135 3,
136 'Floating point exception')
137
138 @unittest.skipIf(not hasattr(faulthandler, '_sigbus'),
139 "need faulthandler._sigbus()")
140 def test_sigbus(self):
141 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200142 import faulthandler
143 faulthandler.enable()
144 faulthandler._sigbus()
145 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200146 3,
147 'Bus error')
148
149 @unittest.skipIf(not hasattr(faulthandler, '_sigill'),
150 "need faulthandler._sigill()")
151 def test_sigill(self):
152 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200153 import faulthandler
154 faulthandler.enable()
155 faulthandler._sigill()
156 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200157 3,
158 'Illegal instruction')
159
160 def test_fatal_error(self):
161 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200162 import faulthandler
163 faulthandler._fatal_error(b'xyz')
164 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200165 2,
166 'xyz')
167
Charles-François Natali3391e642011-09-01 23:08:21 +0200168 @unittest.skipIf(sys.platform.startswith('openbsd') and HAVE_THREADS,
169 "Issue #12868: sigaltstack() doesn't work on "
170 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200171 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
172 'need faulthandler._stack_overflow()')
173 def test_stack_overflow(self):
174 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200175 import faulthandler
176 faulthandler.enable()
177 faulthandler._stack_overflow()
178 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200179 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200180 '(?:Segmentation fault|Bus error)',
181 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200182
183 def test_gil_released(self):
184 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200185 import faulthandler
186 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200187 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200188 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200189 3,
Victor Stinner50838282014-09-30 13:54:14 +0200190 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200191
192 def test_enable_file(self):
193 with temporary_filename() as filename:
194 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200195 import faulthandler
196 output = open({filename}, 'wb')
197 faulthandler.enable(output)
198 faulthandler._sigsegv()
199 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200200 4,
Victor Stinner56785392013-06-17 23:37:59 +0200201 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200202 filename=filename)
203
Victor Stinner7bba62f2011-05-07 12:43:00 +0200204 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200205 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200206 import faulthandler
207 faulthandler.enable(all_threads=False)
208 faulthandler._sigsegv()
209 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200210 3,
Victor Stinner56785392013-06-17 23:37:59 +0200211 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200212 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200213
214 def test_disable(self):
215 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200216 import faulthandler
217 faulthandler.enable()
218 faulthandler.disable()
219 faulthandler._sigsegv()
220 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200221 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200222 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200223 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200224 self.assertTrue(not_expected not in stderr,
225 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200226 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200227
228 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200229 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200230 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200231 # regrtest may replace sys.stderr by io.StringIO object, but
232 # faulthandler.enable() requires that sys.stderr has a fileno()
233 # method
Victor Stinner72488502011-06-29 23:24:31 +0200234 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200235
236 was_enabled = faulthandler.is_enabled()
237 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200238 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200239 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200240 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200241 self.assertFalse(faulthandler.is_enabled())
242 finally:
243 if was_enabled:
244 faulthandler.enable()
245 else:
246 faulthandler.disable()
247 finally:
248 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200249
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200250 def test_disabled_by_default(self):
251 # By default, the module should be disabled
252 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinneref8115e2013-06-25 21:54:17 +0200253 args = (sys.executable, '-E', '-c', code)
Victor Stinner88983502013-09-08 11:36:23 +0200254 # don't use assert_python_ok() because it always enable faulthandler
255 output = subprocess.check_output(args)
256 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200257
258 def test_sys_xoptions(self):
259 # Test python -X faulthandler
260 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner88983502013-09-08 11:36:23 +0200261 args = (sys.executable, "-E", "-X", "faulthandler", "-c", code)
262 # don't use assert_python_ok() because it always enable faulthandler
263 output = subprocess.check_output(args)
264 self.assertEqual(output.rstrip(), b"True")
265
266 def test_env_var(self):
267 # empty env var
268 code = "import faulthandler; print(faulthandler.is_enabled())"
269 args = (sys.executable, "-c", code)
270 env = os.environ.copy()
271 env['PYTHONFAULTHANDLER'] = ''
272 # don't use assert_python_ok() because it always enable faulthandler
273 output = subprocess.check_output(args, env=env)
274 self.assertEqual(output.rstrip(), b"False")
275
276 # non-empty env var
277 env = os.environ.copy()
278 env['PYTHONFAULTHANDLER'] = '1'
279 output = subprocess.check_output(args, env=env)
280 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200281
Victor Stinner024e37a2011-03-31 01:31:06 +0200282 def check_dump_traceback(self, filename):
283 """
284 Explicitly call dump_traceback() function and check its output.
285 Raise an error if the output doesn't match the expected format.
286 """
287 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200288 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200289
Victor Stinner6d201682014-08-10 19:50:08 +0200290 def funcB():
291 if {has_filename}:
292 with open({filename}, "wb") as fp:
293 faulthandler.dump_traceback(fp, all_threads=False)
294 else:
295 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200296
Victor Stinner6d201682014-08-10 19:50:08 +0200297 def funcA():
298 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200299
Victor Stinner6d201682014-08-10 19:50:08 +0200300 funcA()
301 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200302 code = code.format(
303 filename=repr(filename),
304 has_filename=bool(filename),
305 )
306 if filename:
307 lineno = 6
308 else:
309 lineno = 8
310 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700311 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200312 ' File "<string>", line %s in funcB' % lineno,
313 ' File "<string>", line 11 in funcA',
314 ' File "<string>", line 13 in <module>'
315 ]
Victor Stinner05585cb2011-03-31 13:29:56 +0200316 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200317 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200318 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200319
320 def test_dump_traceback(self):
321 self.check_dump_traceback(None)
Victor Stinner19402332011-03-31 18:15:52 +0200322
323 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200324 with temporary_filename() as filename:
325 self.check_dump_traceback(filename)
326
Victor Stinner53386d82012-08-01 19:45:34 +0200327 def test_truncate(self):
328 maxlen = 500
329 func_name = 'x' * (maxlen + 50)
330 truncated = 'x' * maxlen + '...'
331 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200332 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200333
Victor Stinner6d201682014-08-10 19:50:08 +0200334 def {func_name}():
335 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200336
Victor Stinner6d201682014-08-10 19:50:08 +0200337 {func_name}()
338 """
Victor Stinner53386d82012-08-01 19:45:34 +0200339 code = code.format(
340 func_name=func_name,
341 )
342 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700343 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200344 ' File "<string>", line 4 in %s' % truncated,
345 ' File "<string>", line 6 in <module>'
346 ]
347 trace, exitcode = self.get_output(code)
348 self.assertEqual(trace, expected)
349 self.assertEqual(exitcode, 0)
350
Victor Stinnerff4cd882011-04-07 11:50:25 +0200351 @unittest.skipIf(not HAVE_THREADS, 'need threads')
Victor Stinner024e37a2011-03-31 01:31:06 +0200352 def check_dump_traceback_threads(self, filename):
353 """
354 Call explicitly dump_traceback(all_threads=True) and check the output.
355 Raise an error if the output doesn't match the expected format.
356 """
357 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200358 import faulthandler
359 from threading import Thread, Event
360 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200361
Victor Stinner6d201682014-08-10 19:50:08 +0200362 def dump():
363 if {filename}:
364 with open({filename}, "wb") as fp:
365 faulthandler.dump_traceback(fp, all_threads=True)
366 else:
367 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200368
Victor Stinner6d201682014-08-10 19:50:08 +0200369 class Waiter(Thread):
370 # avoid blocking if the main thread raises an exception.
371 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200372
Victor Stinner6d201682014-08-10 19:50:08 +0200373 def __init__(self):
374 Thread.__init__(self)
375 self.running = Event()
376 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200377
Victor Stinner6d201682014-08-10 19:50:08 +0200378 def run(self):
379 self.running.set()
380 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200381
Victor Stinner6d201682014-08-10 19:50:08 +0200382 waiter = Waiter()
383 waiter.start()
384 waiter.running.wait()
385 dump()
386 waiter.stop.set()
387 waiter.join()
388 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200389 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200390 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200391 output = '\n'.join(output)
392 if filename:
393 lineno = 8
394 else:
395 lineno = 10
396 regex = """
Victor Stinner6d201682014-08-10 19:50:08 +0200397 ^Thread 0x[0-9a-f]+ \(most recent call first\):
398 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
399 ){{1,3}} File "<string>", line 23 in run
400 File ".*threading.py", line [0-9]+ in _bootstrap_inner
401 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200402
Victor Stinner6d201682014-08-10 19:50:08 +0200403 Current thread XXX \(most recent call first\):
404 File "<string>", line {lineno} in dump
405 File "<string>", line 28 in <module>$
406 """
407 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200408 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200409 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200410
411 def test_dump_traceback_threads(self):
412 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200413
414 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200415 with temporary_filename() as filename:
416 self.check_dump_traceback_threads(filename)
417
Georg Brandldeb92b52012-09-22 08:58:55 +0200418 def _check_dump_traceback_later(self, repeat, cancel, filename, loops):
Victor Stinner024e37a2011-03-31 01:31:06 +0200419 """
420 Check how many times the traceback is written in timeout x 2.5 seconds,
421 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
422 on repeat and cancel options.
423
424 Raise an error if the output doesn't match the expect format.
425 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200426 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200427 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200428 import faulthandler
429 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200430
Victor Stinner6d201682014-08-10 19:50:08 +0200431 def func(timeout, repeat, cancel, file, loops):
432 for loop in range(loops):
433 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
434 if cancel:
435 faulthandler.cancel_dump_traceback_later()
436 time.sleep(timeout * 5)
437 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200438
Victor Stinner6d201682014-08-10 19:50:08 +0200439 timeout = {timeout}
440 repeat = {repeat}
441 cancel = {cancel}
442 loops = {loops}
443 if {has_filename}:
444 file = open({filename}, "wb")
445 else:
446 file = None
447 func(timeout, repeat, cancel, file, loops)
448 if file is not None:
449 file.close()
450 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200451 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200452 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200453 repeat=repeat,
454 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200455 loops=loops,
456 has_filename=bool(filename),
457 filename=repr(filename),
Victor Stinner024e37a2011-03-31 01:31:06 +0200458 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200459 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200460 trace = '\n'.join(trace)
461
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200462 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200463 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200464 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200465 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700466 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner301f3f02011-06-01 13:49:12 +0200467 regex = expected_traceback(9, 20, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200468 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200469 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200470 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200471 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200472
Georg Brandldeb92b52012-09-22 08:58:55 +0200473 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
474 'need faulthandler.dump_traceback_later()')
475 def check_dump_traceback_later(self, repeat=False, cancel=False,
Victor Stinnerde10f402011-04-08 12:57:06 +0200476 file=False, twice=False):
477 if twice:
478 loops = 2
479 else:
480 loops = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200481 if file:
482 with temporary_filename() as filename:
Georg Brandldeb92b52012-09-22 08:58:55 +0200483 self._check_dump_traceback_later(repeat, cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200484 filename, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200485 else:
Georg Brandldeb92b52012-09-22 08:58:55 +0200486 self._check_dump_traceback_later(repeat, cancel, None, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200487
Georg Brandldeb92b52012-09-22 08:58:55 +0200488 def test_dump_traceback_later(self):
489 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200490
Georg Brandldeb92b52012-09-22 08:58:55 +0200491 def test_dump_traceback_later_repeat(self):
492 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200493
Georg Brandldeb92b52012-09-22 08:58:55 +0200494 def test_dump_traceback_later_cancel(self):
495 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200496
Georg Brandldeb92b52012-09-22 08:58:55 +0200497 def test_dump_traceback_later_file(self):
498 self.check_dump_traceback_later(file=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200499
Georg Brandldeb92b52012-09-22 08:58:55 +0200500 def test_dump_traceback_later_twice(self):
501 self.check_dump_traceback_later(twice=True)
Victor Stinnerde10f402011-04-08 12:57:06 +0200502
Victor Stinner024e37a2011-03-31 01:31:06 +0200503 @unittest.skipIf(not hasattr(faulthandler, "register"),
504 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200505 def check_register(self, filename=False, all_threads=False,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200506 unregister=False, chain=False):
Victor Stinner024e37a2011-03-31 01:31:06 +0200507 """
508 Register a handler displaying the traceback on a user signal. Raise the
509 signal and check the written traceback.
510
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200511 If chain is True, check that the previous signal handler is called.
512
Victor Stinner024e37a2011-03-31 01:31:06 +0200513 Raise an error if the output doesn't match the expected format.
514 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200515 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200516 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200517 import faulthandler
518 import os
519 import signal
520 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200521
Victor Stinner6d201682014-08-10 19:50:08 +0200522 def func(signum):
523 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200524
Victor Stinner6d201682014-08-10 19:50:08 +0200525 def handler(signum, frame):
526 handler.called = True
527 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200528
Victor Stinner6d201682014-08-10 19:50:08 +0200529 exitcode = 0
530 signum = {signum}
531 unregister = {unregister}
532 chain = {chain}
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200533
Victor Stinner6d201682014-08-10 19:50:08 +0200534 if {has_filename}:
535 file = open({filename}, "wb")
536 else:
537 file = None
538 if chain:
539 signal.signal(signum, handler)
540 faulthandler.register(signum, file=file,
541 all_threads={all_threads}, chain={chain})
542 if unregister:
543 faulthandler.unregister(signum)
544 func(signum)
545 if chain and not handler.called:
546 if file is not None:
547 output = file
548 else:
549 output = sys.stderr
550 print("Error: signal handler not called!", file=output)
551 exitcode = 1
552 if file is not None:
553 file.close()
554 sys.exit(exitcode)
555 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200556 code = code.format(
557 filename=repr(filename),
558 has_filename=bool(filename),
559 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200560 signum=signum,
561 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200562 chain=chain,
Victor Stinner024e37a2011-03-31 01:31:06 +0200563 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200564 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200565 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200566 if not unregister:
567 if all_threads:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700568 regex = 'Current thread XXX \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200569 else:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700570 regex = 'Stack \(most recent call first\):\n'
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200571 regex = expected_traceback(7, 28, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200572 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200573 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200574 self.assertEqual(trace, '')
575 if unregister:
576 self.assertNotEqual(exitcode, 0)
577 else:
578 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200579
580 def test_register(self):
581 self.check_register()
582
Victor Stinnera01ca122011-04-01 12:56:17 +0200583 def test_unregister(self):
584 self.check_register(unregister=True)
585
Victor Stinner024e37a2011-03-31 01:31:06 +0200586 def test_register_file(self):
587 with temporary_filename() as filename:
588 self.check_register(filename=filename)
589
590 def test_register_threads(self):
591 self.check_register(all_threads=True)
592
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200593 def test_register_chain(self):
594 self.check_register(chain=True)
595
Victor Stinnere2d66902014-05-14 17:15:50 +0200596 @contextmanager
597 def check_stderr_none(self):
598 stderr = sys.stderr
599 try:
600 sys.stderr = None
601 with self.assertRaises(RuntimeError) as cm:
602 yield
603 self.assertEqual(str(cm.exception), "sys.stderr is None")
604 finally:
605 sys.stderr = stderr
606
607 def test_stderr_None(self):
608 # Issue #21497: provide an helpful error if sys.stderr is None,
609 # instead of just an attribute error: "None has no attribute fileno".
610 with self.check_stderr_none():
611 faulthandler.enable()
612 with self.check_stderr_none():
613 faulthandler.dump_traceback()
614 if hasattr(faulthandler, 'dump_traceback_later'):
615 with self.check_stderr_none():
616 faulthandler.dump_traceback_later(1e-3)
617 if hasattr(faulthandler, "register"):
618 with self.check_stderr_none():
619 faulthandler.register(signal.SIGUSR1)
620
Victor Stinner024e37a2011-03-31 01:31:06 +0200621
Victor Stinner024e37a2011-03-31 01:31:06 +0200622if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400623 unittest.main()