blob: 35129b6a71254475b6d0586a1b8b2a1bc612522f [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
Victor Stinner56e8c292014-07-21 12:30:22 +020020try:
21 import _testcapi
22except ImportError:
23 _testcapi = None
Victor Stinnerff4cd882011-04-07 11:50:25 +020024
Victor Stinner44378d42011-04-01 15:37:12 +020025TIMEOUT = 0.5
26
Victor Stinner301f3f02011-06-01 13:49:12 +020027def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020028 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020029 regex += ' File "<string>", line %s in func\n' % lineno1
30 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020031 if 1 < min_count:
32 return '^' + (regex + '\n') * (min_count - 1) + regex
33 else:
34 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020035
36@contextmanager
37def temporary_filename():
38 filename = tempfile.mktemp()
39 try:
40 yield filename
41 finally:
42 support.unlink(filename)
43
44class FaultHandlerTests(unittest.TestCase):
Victor Stinner05585cb2011-03-31 13:29:56 +020045 def get_output(self, code, filename=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020046 """
47 Run the specified code in Python (in a new child process) and read the
48 output from the standard error or from a file (if filename is set).
49 Return the output lines as a list.
50
51 Strip the reference count from the standard error for Python debug
52 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
53 thread XXX".
54 """
Victor Stinner6d201682014-08-10 19:50:08 +020055 code = dedent(code).strip()
Antoine Pitrou77e904e2013-10-08 23:04:32 +020056 with support.SuppressCrashReport():
57 process = script_helper.spawn_python('-c', code)
Victor Stinner024e37a2011-03-31 01:31:06 +020058 stdout, stderr = process.communicate()
59 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020060 output = support.strip_python_stderr(stdout)
61 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020062 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020063 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020064 with open(filename, "rb") as fp:
65 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020066 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020067 output = re.sub('Current thread 0x[0-9a-f]+',
68 'Current thread XXX',
69 output)
Victor Stinner05585cb2011-03-31 13:29:56 +020070 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020071
72 def check_fatal_error(self, code, line_number, name_regex,
Victor Stinner7bba62f2011-05-07 12:43:00 +020073 filename=None, all_threads=True, other_regex=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020074 """
75 Check that the fault handler for fatal errors is enabled and check the
76 traceback from the child process output.
77
78 Raise an error if the output doesn't match the expected format.
79 """
80 if all_threads:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -070081 header = 'Current thread XXX (most recent call first)'
Victor Stinner024e37a2011-03-31 01:31:06 +020082 else:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -070083 header = 'Stack (most recent call first)'
Victor Stinner024e37a2011-03-31 01:31:06 +020084 regex = """
Victor Stinner6d201682014-08-10 19:50:08 +020085 ^Fatal Python error: {name}
Victor Stinner024e37a2011-03-31 01:31:06 +020086
Victor Stinner6d201682014-08-10 19:50:08 +020087 {header}:
88 File "<string>", line {lineno} in <module>
89 """
90 regex = dedent(regex.format(
Victor Stinner024e37a2011-03-31 01:31:06 +020091 lineno=line_number,
92 name=name_regex,
Victor Stinner6d201682014-08-10 19:50:08 +020093 header=re.escape(header))).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +020094 if other_regex:
95 regex += '|' + other_regex
Antoine Pitrou77e904e2013-10-08 23:04:32 +020096 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +020097 output = '\n'.join(output)
98 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +020099 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200100
Victor Stinner330426c2013-07-03 22:29:42 +0200101 @unittest.skipIf(sys.platform.startswith('aix'),
102 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200103 def test_read_null(self):
104 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200105 import faulthandler
106 faulthandler.enable()
107 faulthandler._read_null()
108 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200109 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200110 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
111 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200112
113 def test_sigsegv(self):
114 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200115 import faulthandler
116 faulthandler.enable()
117 faulthandler._sigsegv()
118 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200119 3,
120 'Segmentation fault')
121
Victor Stinnerd727e232011-04-01 12:13:55 +0200122 def test_sigabrt(self):
123 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200124 import faulthandler
125 faulthandler.enable()
126 faulthandler._sigabrt()
127 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200128 3,
129 'Aborted')
130
Victor Stinner024e37a2011-03-31 01:31:06 +0200131 @unittest.skipIf(sys.platform == 'win32',
132 "SIGFPE cannot be caught on Windows")
133 def test_sigfpe(self):
134 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200135 import faulthandler
136 faulthandler.enable()
137 faulthandler._sigfpe()
138 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200139 3,
140 'Floating point exception')
141
Victor Stinner56e8c292014-07-21 12:30:22 +0200142 @unittest.skipIf(_testcapi is None, 'need _testcapi')
143 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
Victor Stinner024e37a2011-03-31 01:31:06 +0200144 def test_sigbus(self):
145 self.check_fatal_error("""
Victor Stinner68e08082014-08-10 19:51:05 +0200146 import _testcapi
Victor Stinner6d201682014-08-10 19:50:08 +0200147 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200148 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200149
Victor Stinner6d201682014-08-10 19:50:08 +0200150 faulthandler.enable()
Victor Stinner68e08082014-08-10 19:51:05 +0200151 _testcapi.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200152 """,
Victor Stinner56e8c292014-07-21 12:30:22 +0200153 6,
Victor Stinner024e37a2011-03-31 01:31:06 +0200154 'Bus error')
155
Victor Stinner56e8c292014-07-21 12:30:22 +0200156 @unittest.skipIf(_testcapi is None, 'need _testcapi')
157 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
Victor Stinner024e37a2011-03-31 01:31:06 +0200158 def test_sigill(self):
159 self.check_fatal_error("""
Victor Stinner68e08082014-08-10 19:51:05 +0200160 import _testcapi
Victor Stinner6d201682014-08-10 19:50:08 +0200161 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200162 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200163
Victor Stinner6d201682014-08-10 19:50:08 +0200164 faulthandler.enable()
Victor Stinner68e08082014-08-10 19:51:05 +0200165 _testcapi.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200166 """,
Victor Stinner56e8c292014-07-21 12:30:22 +0200167 6,
Victor Stinner024e37a2011-03-31 01:31:06 +0200168 'Illegal instruction')
169
170 def test_fatal_error(self):
171 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200172 import faulthandler
173 faulthandler._fatal_error(b'xyz')
174 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200175 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("""
Victor Stinner6d201682014-08-10 19:50:08 +0200185 import faulthandler
186 faulthandler.enable()
187 faulthandler._stack_overflow()
188 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200189 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("""
Victor Stinner6d201682014-08-10 19:50:08 +0200195 import faulthandler
196 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200197 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200198 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200199 3,
Victor Stinner50838282014-09-30 13:54:14 +0200200 'Segmentation fault')
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("""
Victor Stinner6d201682014-08-10 19:50:08 +0200205 import faulthandler
206 output = open({filename}, 'wb')
207 faulthandler.enable(output)
208 faulthandler._sigsegv()
209 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200210 4,
Victor Stinner56785392013-06-17 23:37:59 +0200211 'Segmentation fault',
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("""
Victor Stinner6d201682014-08-10 19:50:08 +0200216 import faulthandler
217 faulthandler.enable(all_threads=False)
218 faulthandler._sigsegv()
219 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200220 3,
Victor Stinner56785392013-06-17 23:37:59 +0200221 'Segmentation fault',
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 = """
Victor Stinner6d201682014-08-10 19:50:08 +0200226 import faulthandler
227 faulthandler.enable()
228 faulthandler.disable()
229 faulthandler._sigsegv()
230 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200231 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200232 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200233 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200234 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())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800263 args = filter(None, (sys.executable,
264 "-E" if sys.flags.ignore_environment else "",
265 "-c", code))
266 env = os.environ.copy()
267 env.pop("PYTHONFAULTHANDLER", None)
268 # don't use assert_python_ok() because it always enables faulthandler
269 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200270 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200271
272 def test_sys_xoptions(self):
273 # Test python -X faulthandler
274 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800275 args = filter(None, (sys.executable,
276 "-E" if sys.flags.ignore_environment else "",
277 "-X", "faulthandler", "-c", code))
278 env = os.environ.copy()
279 env.pop("PYTHONFAULTHANDLER", None)
280 # don't use assert_python_ok() because it always enables faulthandler
281 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200282 self.assertEqual(output.rstrip(), b"True")
283
284 def test_env_var(self):
285 # empty env var
286 code = "import faulthandler; print(faulthandler.is_enabled())"
287 args = (sys.executable, "-c", code)
288 env = os.environ.copy()
289 env['PYTHONFAULTHANDLER'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800290 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200291 output = subprocess.check_output(args, env=env)
292 self.assertEqual(output.rstrip(), b"False")
293
294 # non-empty env var
295 env = os.environ.copy()
296 env['PYTHONFAULTHANDLER'] = '1'
297 output = subprocess.check_output(args, env=env)
298 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200299
Victor Stinner024e37a2011-03-31 01:31:06 +0200300 def check_dump_traceback(self, filename):
301 """
302 Explicitly call dump_traceback() function and check its output.
303 Raise an error if the output doesn't match the expected format.
304 """
305 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200306 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200307
Victor Stinner6d201682014-08-10 19:50:08 +0200308 def funcB():
309 if {has_filename}:
310 with open({filename}, "wb") as fp:
311 faulthandler.dump_traceback(fp, all_threads=False)
312 else:
313 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200314
Victor Stinner6d201682014-08-10 19:50:08 +0200315 def funcA():
316 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200317
Victor Stinner6d201682014-08-10 19:50:08 +0200318 funcA()
319 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200320 code = code.format(
321 filename=repr(filename),
322 has_filename=bool(filename),
323 )
324 if filename:
325 lineno = 6
326 else:
327 lineno = 8
328 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700329 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200330 ' File "<string>", line %s in funcB' % lineno,
331 ' File "<string>", line 11 in funcA',
332 ' File "<string>", line 13 in <module>'
333 ]
Victor Stinner05585cb2011-03-31 13:29:56 +0200334 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200335 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200336 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200337
338 def test_dump_traceback(self):
339 self.check_dump_traceback(None)
Victor Stinner19402332011-03-31 18:15:52 +0200340
341 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200342 with temporary_filename() as filename:
343 self.check_dump_traceback(filename)
344
Victor Stinner53386d82012-08-01 19:45:34 +0200345 def test_truncate(self):
346 maxlen = 500
347 func_name = 'x' * (maxlen + 50)
348 truncated = 'x' * maxlen + '...'
349 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200350 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200351
Victor Stinner6d201682014-08-10 19:50:08 +0200352 def {func_name}():
353 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200354
Victor Stinner6d201682014-08-10 19:50:08 +0200355 {func_name}()
356 """
Victor Stinner53386d82012-08-01 19:45:34 +0200357 code = code.format(
358 func_name=func_name,
359 )
360 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700361 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200362 ' File "<string>", line 4 in %s' % truncated,
363 ' File "<string>", line 6 in <module>'
364 ]
365 trace, exitcode = self.get_output(code)
366 self.assertEqual(trace, expected)
367 self.assertEqual(exitcode, 0)
368
Victor Stinnerff4cd882011-04-07 11:50:25 +0200369 @unittest.skipIf(not HAVE_THREADS, 'need threads')
Victor Stinner024e37a2011-03-31 01:31:06 +0200370 def check_dump_traceback_threads(self, filename):
371 """
372 Call explicitly dump_traceback(all_threads=True) and check the output.
373 Raise an error if the output doesn't match the expected format.
374 """
375 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200376 import faulthandler
377 from threading import Thread, Event
378 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200379
Victor Stinner6d201682014-08-10 19:50:08 +0200380 def dump():
381 if {filename}:
382 with open({filename}, "wb") as fp:
383 faulthandler.dump_traceback(fp, all_threads=True)
384 else:
385 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200386
Victor Stinner6d201682014-08-10 19:50:08 +0200387 class Waiter(Thread):
388 # avoid blocking if the main thread raises an exception.
389 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200390
Victor Stinner6d201682014-08-10 19:50:08 +0200391 def __init__(self):
392 Thread.__init__(self)
393 self.running = Event()
394 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200395
Victor Stinner6d201682014-08-10 19:50:08 +0200396 def run(self):
397 self.running.set()
398 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200399
Victor Stinner6d201682014-08-10 19:50:08 +0200400 waiter = Waiter()
401 waiter.start()
402 waiter.running.wait()
403 dump()
404 waiter.stop.set()
405 waiter.join()
406 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200407 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200408 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200409 output = '\n'.join(output)
410 if filename:
411 lineno = 8
412 else:
413 lineno = 10
414 regex = """
Victor Stinner6d201682014-08-10 19:50:08 +0200415 ^Thread 0x[0-9a-f]+ \(most recent call first\):
416 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
417 ){{1,3}} File "<string>", line 23 in run
418 File ".*threading.py", line [0-9]+ in _bootstrap_inner
419 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200420
Victor Stinner6d201682014-08-10 19:50:08 +0200421 Current thread XXX \(most recent call first\):
422 File "<string>", line {lineno} in dump
423 File "<string>", line 28 in <module>$
424 """
425 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200426 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200427 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200428
429 def test_dump_traceback_threads(self):
430 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200431
432 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200433 with temporary_filename() as filename:
434 self.check_dump_traceback_threads(filename)
435
Georg Brandldeb92b52012-09-22 08:58:55 +0200436 def _check_dump_traceback_later(self, repeat, cancel, filename, loops):
Victor Stinner024e37a2011-03-31 01:31:06 +0200437 """
438 Check how many times the traceback is written in timeout x 2.5 seconds,
439 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
440 on repeat and cancel options.
441
442 Raise an error if the output doesn't match the expect format.
443 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200444 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200445 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200446 import faulthandler
447 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200448
Victor Stinner6d201682014-08-10 19:50:08 +0200449 def func(timeout, repeat, cancel, file, loops):
450 for loop in range(loops):
451 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
452 if cancel:
453 faulthandler.cancel_dump_traceback_later()
454 time.sleep(timeout * 5)
455 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200456
Victor Stinner6d201682014-08-10 19:50:08 +0200457 timeout = {timeout}
458 repeat = {repeat}
459 cancel = {cancel}
460 loops = {loops}
461 if {has_filename}:
462 file = open({filename}, "wb")
463 else:
464 file = None
465 func(timeout, repeat, cancel, file, loops)
466 if file is not None:
467 file.close()
468 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200469 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200470 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200471 repeat=repeat,
472 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200473 loops=loops,
474 has_filename=bool(filename),
475 filename=repr(filename),
Victor Stinner024e37a2011-03-31 01:31:06 +0200476 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200477 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200478 trace = '\n'.join(trace)
479
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200480 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200481 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200482 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200483 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700484 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner301f3f02011-06-01 13:49:12 +0200485 regex = expected_traceback(9, 20, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200486 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200487 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200488 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200489 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200490
Georg Brandldeb92b52012-09-22 08:58:55 +0200491 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
492 'need faulthandler.dump_traceback_later()')
493 def check_dump_traceback_later(self, repeat=False, cancel=False,
Victor Stinnerde10f402011-04-08 12:57:06 +0200494 file=False, twice=False):
495 if twice:
496 loops = 2
497 else:
498 loops = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200499 if file:
500 with temporary_filename() as filename:
Georg Brandldeb92b52012-09-22 08:58:55 +0200501 self._check_dump_traceback_later(repeat, cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200502 filename, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200503 else:
Georg Brandldeb92b52012-09-22 08:58:55 +0200504 self._check_dump_traceback_later(repeat, cancel, None, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200505
Georg Brandldeb92b52012-09-22 08:58:55 +0200506 def test_dump_traceback_later(self):
507 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200508
Georg Brandldeb92b52012-09-22 08:58:55 +0200509 def test_dump_traceback_later_repeat(self):
510 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200511
Georg Brandldeb92b52012-09-22 08:58:55 +0200512 def test_dump_traceback_later_cancel(self):
513 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200514
Georg Brandldeb92b52012-09-22 08:58:55 +0200515 def test_dump_traceback_later_file(self):
516 self.check_dump_traceback_later(file=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200517
Georg Brandldeb92b52012-09-22 08:58:55 +0200518 def test_dump_traceback_later_twice(self):
519 self.check_dump_traceback_later(twice=True)
Victor Stinnerde10f402011-04-08 12:57:06 +0200520
Victor Stinner024e37a2011-03-31 01:31:06 +0200521 @unittest.skipIf(not hasattr(faulthandler, "register"),
522 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200523 def check_register(self, filename=False, all_threads=False,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200524 unregister=False, chain=False):
Victor Stinner024e37a2011-03-31 01:31:06 +0200525 """
526 Register a handler displaying the traceback on a user signal. Raise the
527 signal and check the written traceback.
528
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200529 If chain is True, check that the previous signal handler is called.
530
Victor Stinner024e37a2011-03-31 01:31:06 +0200531 Raise an error if the output doesn't match the expected format.
532 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200533 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200534 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200535 import faulthandler
536 import os
537 import signal
538 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200539
Victor Stinner6d201682014-08-10 19:50:08 +0200540 def func(signum):
541 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200542
Victor Stinner6d201682014-08-10 19:50:08 +0200543 def handler(signum, frame):
544 handler.called = True
545 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200546
Victor Stinner6d201682014-08-10 19:50:08 +0200547 exitcode = 0
548 signum = {signum}
549 unregister = {unregister}
550 chain = {chain}
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200551
Victor Stinner6d201682014-08-10 19:50:08 +0200552 if {has_filename}:
553 file = open({filename}, "wb")
554 else:
555 file = None
556 if chain:
557 signal.signal(signum, handler)
558 faulthandler.register(signum, file=file,
559 all_threads={all_threads}, chain={chain})
560 if unregister:
561 faulthandler.unregister(signum)
562 func(signum)
563 if chain and not handler.called:
564 if file is not None:
565 output = file
566 else:
567 output = sys.stderr
568 print("Error: signal handler not called!", file=output)
569 exitcode = 1
570 if file is not None:
571 file.close()
572 sys.exit(exitcode)
573 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200574 code = code.format(
575 filename=repr(filename),
576 has_filename=bool(filename),
577 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200578 signum=signum,
579 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200580 chain=chain,
Victor Stinner024e37a2011-03-31 01:31:06 +0200581 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200582 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200583 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200584 if not unregister:
585 if all_threads:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700586 regex = 'Current thread XXX \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200587 else:
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700588 regex = 'Stack \(most recent call first\):\n'
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200589 regex = expected_traceback(7, 28, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200590 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200591 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200592 self.assertEqual(trace, '')
593 if unregister:
594 self.assertNotEqual(exitcode, 0)
595 else:
596 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200597
598 def test_register(self):
599 self.check_register()
600
Victor Stinnera01ca122011-04-01 12:56:17 +0200601 def test_unregister(self):
602 self.check_register(unregister=True)
603
Victor Stinner024e37a2011-03-31 01:31:06 +0200604 def test_register_file(self):
605 with temporary_filename() as filename:
606 self.check_register(filename=filename)
607
608 def test_register_threads(self):
609 self.check_register(all_threads=True)
610
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200611 def test_register_chain(self):
612 self.check_register(chain=True)
613
Victor Stinnere2d66902014-05-14 17:15:50 +0200614 @contextmanager
615 def check_stderr_none(self):
616 stderr = sys.stderr
617 try:
618 sys.stderr = None
619 with self.assertRaises(RuntimeError) as cm:
620 yield
621 self.assertEqual(str(cm.exception), "sys.stderr is None")
622 finally:
623 sys.stderr = stderr
624
625 def test_stderr_None(self):
626 # Issue #21497: provide an helpful error if sys.stderr is None,
627 # instead of just an attribute error: "None has no attribute fileno".
628 with self.check_stderr_none():
629 faulthandler.enable()
630 with self.check_stderr_none():
631 faulthandler.dump_traceback()
632 if hasattr(faulthandler, 'dump_traceback_later'):
633 with self.check_stderr_none():
634 faulthandler.dump_traceback_later(1e-3)
635 if hasattr(faulthandler, "register"):
636 with self.check_stderr_none():
637 faulthandler.register(signal.SIGUSR1)
638
Victor Stinner024e37a2011-03-31 01:31:06 +0200639
Victor Stinner024e37a2011-03-31 01:31:06 +0200640if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400641 unittest.main()