blob: ee3f41a108a14c8a75c4dad5ae88945f8e995ed2 [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 Stinner250035d2021-01-18 20:47:13 +01005import re
Victor Stinner024e37a2011-03-31 01:31:06 +02006import signal
7import subprocess
8import sys
Gregory P. Smithb474e672018-12-30 17:05:36 -08009import sysconfig
Berker Peksagce643912015-05-06 06:33:17 +030010from test import support
Hai Shi79bb2c92020-08-06 19:51:29 +080011from test.support import os_helper
Victor Stinner937ee9e2018-06-26 02:11:06 +020012from test.support import script_helper, is_android
Victor Stinner024e37a2011-03-31 01:31:06 +020013import tempfile
14import unittest
Victor Stinner6d201682014-08-10 19:50:08 +020015from textwrap import dedent
Victor Stinner024e37a2011-03-31 01:31:06 +020016
Victor Stinnerff4cd882011-04-07 11:50:25 +020017try:
Victor Stinner56e8c292014-07-21 12:30:22 +020018 import _testcapi
19except ImportError:
20 _testcapi = None
Victor Stinnerff4cd882011-04-07 11:50:25 +020021
Victor Stinner44378d42011-04-01 15:37:12 +020022TIMEOUT = 0.5
Victor Stinner937ee9e2018-06-26 02:11:06 +020023MS_WINDOWS = (os.name == 'nt')
Gregory P. Smith30e02322018-12-30 18:09:26 -080024_cflags = sysconfig.get_config_var('CFLAGS') or ''
25_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
26UB_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080027 '-fsanitize=undefined' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080028 '--with-undefined-behavior-sanitizer' in _config_args
Gregory P. Smithb474e672018-12-30 17:05:36 -080029)
Gregory P. Smith30e02322018-12-30 18:09:26 -080030MEMORY_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080031 '-fsanitize=memory' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080032 '--with-memory-sanitizer' in _config_args
33)
34
Victor Stinner44378d42011-04-01 15:37:12 +020035
Victor Stinner301f3f02011-06-01 13:49:12 +020036def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020037 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020038 regex += ' File "<string>", line %s in func\n' % lineno1
39 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020040 if 1 < min_count:
41 return '^' + (regex + '\n') * (min_count - 1) + regex
42 else:
43 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020044
xdegayeef838062017-11-29 11:43:23 +010045def skip_segfault_on_android(test):
46 # Issue #32138: Raising SIGSEGV on Android may not cause a crash.
Victor Stinner937ee9e2018-06-26 02:11:06 +020047 return unittest.skipIf(is_android,
xdegayeef838062017-11-29 11:43:23 +010048 'raising SIGSEGV on Android is unreliable')(test)
49
Victor Stinner024e37a2011-03-31 01:31:06 +020050@contextmanager
51def temporary_filename():
52 filename = tempfile.mktemp()
53 try:
54 yield filename
55 finally:
Hai Shi79bb2c92020-08-06 19:51:29 +080056 os_helper.unlink(filename)
Victor Stinner024e37a2011-03-31 01:31:06 +020057
58class FaultHandlerTests(unittest.TestCase):
Victor Stinner95bb7142015-03-12 15:32:03 +010059 def get_output(self, code, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020060 """
61 Run the specified code in Python (in a new child process) and read the
62 output from the standard error or from a file (if filename is set).
63 Return the output lines as a list.
64
65 Strip the reference count from the standard error for Python debug
66 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
67 thread XXX".
68 """
Victor Stinner6d201682014-08-10 19:50:08 +020069 code = dedent(code).strip()
Victor Stinner95bb7142015-03-12 15:32:03 +010070 pass_fds = []
71 if fd is not None:
72 pass_fds.append(fd)
Antoine Pitrou77e904e2013-10-08 23:04:32 +020073 with support.SuppressCrashReport():
Victor Stinner95bb7142015-03-12 15:32:03 +010074 process = script_helper.spawn_python('-c', code, pass_fds=pass_fds)
Victor Stinner861d9ab2016-03-16 22:45:24 +010075 with process:
Victor Stinner6cac1132019-12-08 08:38:16 +010076 output, stderr = process.communicate()
Victor Stinner861d9ab2016-03-16 22:45:24 +010077 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020078 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020079 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020080 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020081 with open(filename, "rb") as fp:
82 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020083 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010084 elif fd is not None:
85 self.assertEqual(output, '')
86 os.lseek(fd, os.SEEK_SET, 0)
87 with open(fd, "rb", closefd=False) as fp:
88 output = fp.read()
89 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020090 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020091
Victor Stinner9b0bbb92021-06-21 14:23:13 +020092 def check_error(self, code, lineno, fatal_error, *,
Victor Stinner404cdc52016-03-23 10:39:17 +010093 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020094 fd=None, know_current_thread=True,
Victor Stinner9b0bbb92021-06-21 14:23:13 +020095 py_fatal_error=False,
96 garbage_collecting=False,
97 function='<module>'):
Victor Stinner024e37a2011-03-31 01:31:06 +020098 """
99 Check that the fault handler for fatal errors is enabled and check the
100 traceback from the child process output.
101
102 Raise an error if the output doesn't match the expected format.
103 """
104 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100105 if know_current_thread:
106 header = 'Current thread 0x[0-9a-f]+'
107 else:
108 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200109 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100110 header = 'Stack'
Victor Stinner9b0bbb92021-06-21 14:23:13 +0200111 regex = [f'^{fatal_error}']
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200112 if py_fatal_error:
Victor Stinner9b0bbb92021-06-21 14:23:13 +0200113 regex.append("Python runtime state: initialized")
114 regex.append('')
115 regex.append(fr'{header} \(most recent call first\):')
116 if garbage_collecting:
117 regex.append(' Garbage-collecting')
118 regex.append(fr' File "<string>", line {lineno} in {function}')
119 regex = '\n'.join(regex)
120
Victor Stinnerf0480752011-03-31 11:34:08 +0200121 if other_regex:
Victor Stinner9b0bbb92021-06-21 14:23:13 +0200122 regex = f'(?:{regex}|{other_regex})'
123
124 # Enable MULTILINE flag
125 regex = f'(?m){regex}'
Victor Stinner95bb7142015-03-12 15:32:03 +0100126 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200127 output = '\n'.join(output)
128 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200129 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200130
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100131 def check_fatal_error(self, code, line_number, name_regex, func=None, **kw):
132 if func:
133 name_regex = '%s: %s' % (func, name_regex)
Victor Stinner404cdc52016-03-23 10:39:17 +0100134 fatal_error = 'Fatal Python error: %s' % name_regex
135 self.check_error(code, line_number, fatal_error, **kw)
136
137 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100138 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100139 self.check_error(code, line_number, fatal_error, **kw)
140
Victor Stinner330426c2013-07-03 22:29:42 +0200141 @unittest.skipIf(sys.platform.startswith('aix'),
142 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200143 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200144 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100145 self.check_fatal_error("""
146 import faulthandler
147 faulthandler.enable()
148 faulthandler._read_null()
149 """,
150 3,
151 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
152 '(?:Segmentation fault'
153 '|Bus error'
154 '|Illegal instruction)')
155 else:
156 self.check_windows_exception("""
157 import faulthandler
158 faulthandler.enable()
159 faulthandler._read_null()
160 """,
161 3,
162 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200163
xdegayeef838062017-11-29 11:43:23 +0100164 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200165 def test_sigsegv(self):
166 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200167 import faulthandler
168 faulthandler.enable()
169 faulthandler._sigsegv()
170 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200171 3,
172 'Segmentation fault')
173
Victor Stinner9b0bbb92021-06-21 14:23:13 +0200174 @skip_segfault_on_android
175 def test_gc(self):
176 # bpo-44466: Detect if the GC is running
177 self.check_fatal_error("""
178 import faulthandler
179 import gc
180 import sys
181
182 faulthandler.enable()
183
184 class RefCycle:
185 def __del__(self):
186 faulthandler._sigsegv()
187
188 # create a reference cycle which triggers a fatal
189 # error in a destructor
190 a = RefCycle()
191 b = RefCycle()
192 a.b = b
193 b.a = a
194
195 # Delete the objects, not the cycle
196 a = None
197 b = None
198
199 # Break the reference cycle: call __del__()
200 gc.collect()
201
202 # Should not reach this line
203 print("exit", file=sys.stderr)
204 """,
205 9,
206 'Segmentation fault',
207 function='__del__',
208 garbage_collecting=True)
209
Victor Stinner861d9ab2016-03-16 22:45:24 +0100210 def test_fatal_error_c_thread(self):
211 self.check_fatal_error("""
212 import faulthandler
213 faulthandler.enable()
214 faulthandler._fatal_error_c_thread()
215 """,
216 3,
217 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200218 know_current_thread=False,
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100219 func='faulthandler_fatal_error_thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200220 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100221
Victor Stinnerd727e232011-04-01 12:13:55 +0200222 def test_sigabrt(self):
223 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200224 import faulthandler
225 faulthandler.enable()
226 faulthandler._sigabrt()
227 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200228 3,
229 'Aborted')
230
Victor Stinner024e37a2011-03-31 01:31:06 +0200231 @unittest.skipIf(sys.platform == 'win32',
232 "SIGFPE cannot be caught on Windows")
233 def test_sigfpe(self):
234 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200235 import faulthandler
236 faulthandler.enable()
237 faulthandler._sigfpe()
238 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200239 3,
240 'Floating point exception')
241
Victor Stinner56e8c292014-07-21 12:30:22 +0200242 @unittest.skipIf(_testcapi is None, 'need _testcapi')
243 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100244 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200245 def test_sigbus(self):
246 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200247 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200248 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200249
Victor Stinner6d201682014-08-10 19:50:08 +0200250 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800251 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200252 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800253 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200254 'Bus error')
255
Victor Stinner56e8c292014-07-21 12:30:22 +0200256 @unittest.skipIf(_testcapi is None, 'need _testcapi')
257 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100258 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200259 def test_sigill(self):
260 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200261 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200262 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200263
Victor Stinner6d201682014-08-10 19:50:08 +0200264 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800265 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200266 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800267 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200268 'Illegal instruction')
269
Victor Stinnere2320252021-01-18 18:24:29 +0100270 def check_fatal_error_func(self, release_gil):
271 # Test that Py_FatalError() dumps a traceback
272 with support.SuppressCrashReport():
273 self.check_fatal_error(f"""
274 import _testcapi
275 _testcapi.fatal_error(b'xyz', {release_gil})
276 """,
277 2,
278 'xyz',
279 func='test_fatal_error',
280 py_fatal_error=True)
281
Victor Stinner024e37a2011-03-31 01:31:06 +0200282 def test_fatal_error(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100283 self.check_fatal_error_func(False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200284
Victor Stinner57003f82016-03-15 17:23:35 +0100285 def test_fatal_error_without_gil(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100286 self.check_fatal_error_func(True)
Victor Stinner57003f82016-03-15 17:23:35 +0100287
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200288 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200289 "Issue #12868: sigaltstack() doesn't work on "
290 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200291 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
292 'need faulthandler._stack_overflow()')
293 def test_stack_overflow(self):
294 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200295 import faulthandler
296 faulthandler.enable()
297 faulthandler._stack_overflow()
298 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200299 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200300 '(?:Segmentation fault|Bus error)',
301 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200302
xdegayeef838062017-11-29 11:43:23 +0100303 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200304 def test_gil_released(self):
305 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200306 import faulthandler
307 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200308 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200309 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200310 3,
Victor Stinner50838282014-09-30 13:54:14 +0200311 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200312
Gregory P. Smith30e02322018-12-30 18:09:26 -0800313 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800314 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100315 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200316 def test_enable_file(self):
317 with temporary_filename() as filename:
318 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200319 import faulthandler
320 output = open({filename}, 'wb')
321 faulthandler.enable(output)
322 faulthandler._sigsegv()
323 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200324 4,
Victor Stinner56785392013-06-17 23:37:59 +0200325 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200326 filename=filename)
327
Victor Stinnerff2a6612015-03-13 11:01:30 +0100328 @unittest.skipIf(sys.platform == "win32",
329 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800330 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800331 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100332 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100333 def test_enable_fd(self):
334 with tempfile.TemporaryFile('wb+') as fp:
335 fd = fp.fileno()
336 self.check_fatal_error("""
337 import faulthandler
338 import sys
339 faulthandler.enable(%s)
340 faulthandler._sigsegv()
341 """ % fd,
342 4,
343 'Segmentation fault',
344 fd=fd)
345
xdegayeef838062017-11-29 11:43:23 +0100346 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200347 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200348 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200349 import faulthandler
350 faulthandler.enable(all_threads=False)
351 faulthandler._sigsegv()
352 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200353 3,
Victor Stinner56785392013-06-17 23:37:59 +0200354 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200355 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200356
xdegayeef838062017-11-29 11:43:23 +0100357 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200358 def test_disable(self):
359 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200360 import faulthandler
361 faulthandler.enable()
362 faulthandler.disable()
363 faulthandler._sigsegv()
364 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200365 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200366 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200367 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200368 self.assertTrue(not_expected not in stderr,
369 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200370 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200371
Victor Stinner250035d2021-01-18 20:47:13 +0100372 @skip_segfault_on_android
373 def test_dump_ext_modules(self):
374 code = """
375 import faulthandler
Victor Stinnerdb584bd2021-01-25 13:24:42 +0100376 import sys
377 # Don't filter stdlib module names
Victor Stinner9852cb32021-01-25 23:12:50 +0100378 sys.stdlib_module_names = frozenset()
Victor Stinner250035d2021-01-18 20:47:13 +0100379 faulthandler.enable()
380 faulthandler._sigsegv()
381 """
382 stderr, exitcode = self.get_output(code)
383 stderr = '\n'.join(stderr)
Victor Stinner66f77ca2021-01-19 23:35:27 +0100384 match = re.search(r'^Extension modules:(.*) \(total: [0-9]+\)$',
385 stderr, re.MULTILINE)
Victor Stinner250035d2021-01-18 20:47:13 +0100386 if not match:
387 self.fail(f"Cannot find 'Extension modules:' in {stderr!r}")
388 modules = set(match.group(1).strip().split(', '))
Victor Stinnerdb584bd2021-01-25 13:24:42 +0100389 for name in ('sys', 'faulthandler'):
390 self.assertIn(name, modules)
Victor Stinner250035d2021-01-18 20:47:13 +0100391
Victor Stinner024e37a2011-03-31 01:31:06 +0200392 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200393 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200394 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200395 # regrtest may replace sys.stderr by io.StringIO object, but
396 # faulthandler.enable() requires that sys.stderr has a fileno()
397 # method
Victor Stinner72488502011-06-29 23:24:31 +0200398 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200399
400 was_enabled = faulthandler.is_enabled()
401 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200402 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200403 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200404 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200405 self.assertFalse(faulthandler.is_enabled())
406 finally:
407 if was_enabled:
408 faulthandler.enable()
409 else:
410 faulthandler.disable()
411 finally:
412 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200413
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200414 def test_disabled_by_default(self):
415 # By default, the module should be disabled
416 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100417 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800418 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100419 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200420 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200421
422 def test_sys_xoptions(self):
423 # Test python -X faulthandler
424 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800425 args = filter(None, (sys.executable,
426 "-E" if sys.flags.ignore_environment else "",
427 "-X", "faulthandler", "-c", code))
428 env = os.environ.copy()
429 env.pop("PYTHONFAULTHANDLER", None)
430 # don't use assert_python_ok() because it always enables faulthandler
431 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200432 self.assertEqual(output.rstrip(), b"True")
433
434 def test_env_var(self):
435 # empty env var
436 code = "import faulthandler; print(faulthandler.is_enabled())"
437 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100438 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200439 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100440 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800441 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200442 output = subprocess.check_output(args, env=env)
443 self.assertEqual(output.rstrip(), b"False")
444
445 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100446 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200447 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100448 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200449 output = subprocess.check_output(args, env=env)
450 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200451
Victor Stinner95bb7142015-03-12 15:32:03 +0100452 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200453 """
454 Explicitly call dump_traceback() function and check its output.
455 Raise an error if the output doesn't match the expected format.
456 """
457 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200458 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200459
Victor Stinner95bb7142015-03-12 15:32:03 +0100460 filename = {filename!r}
461 fd = {fd}
462
Victor Stinner6d201682014-08-10 19:50:08 +0200463 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100464 if filename:
465 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200466 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100467 elif fd is not None:
468 faulthandler.dump_traceback(fd,
469 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200470 else:
471 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200472
Victor Stinner6d201682014-08-10 19:50:08 +0200473 def funcA():
474 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200475
Victor Stinner6d201682014-08-10 19:50:08 +0200476 funcA()
477 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200478 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100479 filename=filename,
480 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200481 )
482 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100483 lineno = 9
484 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300485 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200486 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100487 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200488 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700489 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200490 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100491 ' File "<string>", line 17 in funcA',
492 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200493 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100494 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200495 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200496 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200497
498 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100499 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200500
501 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200502 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100503 self.check_dump_traceback(filename=filename)
504
Victor Stinnerff2a6612015-03-13 11:01:30 +0100505 @unittest.skipIf(sys.platform == "win32",
506 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100507 def test_dump_traceback_fd(self):
508 with tempfile.TemporaryFile('wb+') as fp:
509 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200510
Victor Stinner53386d82012-08-01 19:45:34 +0200511 def test_truncate(self):
512 maxlen = 500
513 func_name = 'x' * (maxlen + 50)
514 truncated = 'x' * maxlen + '...'
515 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200516 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200517
Victor Stinner6d201682014-08-10 19:50:08 +0200518 def {func_name}():
519 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200520
Victor Stinner6d201682014-08-10 19:50:08 +0200521 {func_name}()
522 """
Victor Stinner53386d82012-08-01 19:45:34 +0200523 code = code.format(
524 func_name=func_name,
525 )
526 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700527 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200528 ' File "<string>", line 4 in %s' % truncated,
529 ' File "<string>", line 6 in <module>'
530 ]
531 trace, exitcode = self.get_output(code)
532 self.assertEqual(trace, expected)
533 self.assertEqual(exitcode, 0)
534
Victor Stinner024e37a2011-03-31 01:31:06 +0200535 def check_dump_traceback_threads(self, filename):
536 """
537 Call explicitly dump_traceback(all_threads=True) and check the output.
538 Raise an error if the output doesn't match the expected format.
539 """
540 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200541 import faulthandler
542 from threading import Thread, Event
543 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200544
Victor Stinner6d201682014-08-10 19:50:08 +0200545 def dump():
546 if {filename}:
547 with open({filename}, "wb") as fp:
548 faulthandler.dump_traceback(fp, all_threads=True)
549 else:
550 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200551
Victor Stinner6d201682014-08-10 19:50:08 +0200552 class Waiter(Thread):
553 # avoid blocking if the main thread raises an exception.
554 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200555
Victor Stinner6d201682014-08-10 19:50:08 +0200556 def __init__(self):
557 Thread.__init__(self)
558 self.running = Event()
559 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200560
Victor Stinner6d201682014-08-10 19:50:08 +0200561 def run(self):
562 self.running.set()
563 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200564
Victor Stinner6d201682014-08-10 19:50:08 +0200565 waiter = Waiter()
566 waiter.start()
567 waiter.running.wait()
568 dump()
569 waiter.stop.set()
570 waiter.join()
571 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200572 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200573 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200574 output = '\n'.join(output)
575 if filename:
576 lineno = 8
577 else:
578 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400579 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200580 ^Thread 0x[0-9a-f]+ \(most recent call first\):
581 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
582 ){{1,3}} File "<string>", line 23 in run
583 File ".*threading.py", line [0-9]+ in _bootstrap_inner
584 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200585
Victor Stinner861d9ab2016-03-16 22:45:24 +0100586 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200587 File "<string>", line {lineno} in dump
588 File "<string>", line 28 in <module>$
589 """
590 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200591 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200592 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200593
594 def test_dump_traceback_threads(self):
595 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200596
597 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200598 with temporary_filename() as filename:
599 self.check_dump_traceback_threads(filename)
600
Victor Stinner95bb7142015-03-12 15:32:03 +0100601 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
602 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200603 """
604 Check how many times the traceback is written in timeout x 2.5 seconds,
605 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
606 on repeat and cancel options.
607
608 Raise an error if the output doesn't match the expect format.
609 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200610 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200611 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200612 import faulthandler
613 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100614 import sys
615
616 timeout = {timeout}
617 repeat = {repeat}
618 cancel = {cancel}
619 loops = {loops}
620 filename = {filename!r}
621 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200622
Victor Stinner6d201682014-08-10 19:50:08 +0200623 def func(timeout, repeat, cancel, file, loops):
624 for loop in range(loops):
625 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
626 if cancel:
627 faulthandler.cancel_dump_traceback_later()
628 time.sleep(timeout * 5)
629 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200630
Victor Stinner95bb7142015-03-12 15:32:03 +0100631 if filename:
632 file = open(filename, "wb")
633 elif fd is not None:
634 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200635 else:
636 file = None
637 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100638 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200639 file.close()
640 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200641 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200642 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200643 repeat=repeat,
644 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200645 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100646 filename=filename,
647 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200648 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200649 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200650 trace = '\n'.join(trace)
651
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200652 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200653 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200654 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200655 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700656 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100657 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200658 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200659 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200660 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200661 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200662
Georg Brandldeb92b52012-09-22 08:58:55 +0200663 def test_dump_traceback_later(self):
664 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200665
Georg Brandldeb92b52012-09-22 08:58:55 +0200666 def test_dump_traceback_later_repeat(self):
667 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200668
Georg Brandldeb92b52012-09-22 08:58:55 +0200669 def test_dump_traceback_later_cancel(self):
670 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200671
Georg Brandldeb92b52012-09-22 08:58:55 +0200672 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100673 with temporary_filename() as filename:
674 self.check_dump_traceback_later(filename=filename)
675
Victor Stinnerff2a6612015-03-13 11:01:30 +0100676 @unittest.skipIf(sys.platform == "win32",
677 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100678 def test_dump_traceback_later_fd(self):
679 with tempfile.TemporaryFile('wb+') as fp:
680 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200681
Georg Brandldeb92b52012-09-22 08:58:55 +0200682 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100683 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200684
Victor Stinner024e37a2011-03-31 01:31:06 +0200685 @unittest.skipIf(not hasattr(faulthandler, "register"),
686 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200687 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100688 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200689 """
690 Register a handler displaying the traceback on a user signal. Raise the
691 signal and check the written traceback.
692
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200693 If chain is True, check that the previous signal handler is called.
694
Victor Stinner024e37a2011-03-31 01:31:06 +0200695 Raise an error if the output doesn't match the expected format.
696 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200697 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200698 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200699 import faulthandler
700 import os
701 import signal
702 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200703
Victor Stinner95bb7142015-03-12 15:32:03 +0100704 all_threads = {all_threads}
Miss Islington (bot)d194e1e2021-05-03 19:17:23 -0700705 signum = {signum:d}
Victor Stinner95bb7142015-03-12 15:32:03 +0100706 unregister = {unregister}
707 chain = {chain}
708 filename = {filename!r}
709 fd = {fd}
710
Victor Stinner6d201682014-08-10 19:50:08 +0200711 def func(signum):
712 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200713
Victor Stinner6d201682014-08-10 19:50:08 +0200714 def handler(signum, frame):
715 handler.called = True
716 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200717
Victor Stinner95bb7142015-03-12 15:32:03 +0100718 if filename:
719 file = open(filename, "wb")
720 elif fd is not None:
721 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200722 else:
723 file = None
724 if chain:
725 signal.signal(signum, handler)
726 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100727 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200728 if unregister:
729 faulthandler.unregister(signum)
730 func(signum)
731 if chain and not handler.called:
732 if file is not None:
733 output = file
734 else:
735 output = sys.stderr
736 print("Error: signal handler not called!", file=output)
737 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100738 else:
739 exitcode = 0
740 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200741 file.close()
742 sys.exit(exitcode)
743 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200744 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200745 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200746 signum=signum,
747 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200748 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100749 filename=filename,
750 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200751 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200752 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200753 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200754 if not unregister:
755 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400756 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200757 else:
R David Murray44b548d2016-09-08 13:59:53 -0400758 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100759 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200760 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200761 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200762 self.assertEqual(trace, '')
763 if unregister:
764 self.assertNotEqual(exitcode, 0)
765 else:
766 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200767
768 def test_register(self):
769 self.check_register()
770
Victor Stinnera01ca122011-04-01 12:56:17 +0200771 def test_unregister(self):
772 self.check_register(unregister=True)
773
Victor Stinner024e37a2011-03-31 01:31:06 +0200774 def test_register_file(self):
775 with temporary_filename() as filename:
776 self.check_register(filename=filename)
777
Victor Stinnerff2a6612015-03-13 11:01:30 +0100778 @unittest.skipIf(sys.platform == "win32",
779 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100780 def test_register_fd(self):
781 with tempfile.TemporaryFile('wb+') as fp:
782 self.check_register(fd=fp.fileno())
783
Victor Stinner024e37a2011-03-31 01:31:06 +0200784 def test_register_threads(self):
785 self.check_register(all_threads=True)
786
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200787 def test_register_chain(self):
788 self.check_register(chain=True)
789
Victor Stinnere2d66902014-05-14 17:15:50 +0200790 @contextmanager
791 def check_stderr_none(self):
792 stderr = sys.stderr
793 try:
794 sys.stderr = None
795 with self.assertRaises(RuntimeError) as cm:
796 yield
797 self.assertEqual(str(cm.exception), "sys.stderr is None")
798 finally:
799 sys.stderr = stderr
800
801 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300802 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200803 # instead of just an attribute error: "None has no attribute fileno".
804 with self.check_stderr_none():
805 faulthandler.enable()
806 with self.check_stderr_none():
807 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200808 with self.check_stderr_none():
809 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200810 if hasattr(faulthandler, "register"):
811 with self.check_stderr_none():
812 faulthandler.register(signal.SIGUSR1)
813
Victor Stinner937ee9e2018-06-26 02:11:06 +0200814 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100815 def test_raise_exception(self):
816 for exc, name in (
817 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
818 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
819 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
820 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400821 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100822 import faulthandler
823 faulthandler.enable()
824 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400825 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100826 3,
827 name)
828
Victor Stinner937ee9e2018-06-26 02:11:06 +0200829 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700830 def test_ignore_exception(self):
831 for exc_code in (
832 0xE06D7363, # MSC exception ("Emsc")
833 0xE0434352, # COM Callable Runtime exception ("ECCR")
834 ):
835 code = f"""
836 import faulthandler
837 faulthandler.enable()
838 faulthandler._raise_exception({exc_code})
839 """
840 code = dedent(code)
841 output, exitcode = self.get_output(code)
842 self.assertEqual(output, [])
843 self.assertEqual(exitcode, exc_code)
844
Victor Stinner937ee9e2018-06-26 02:11:06 +0200845 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700846 def test_raise_nonfatal_exception(self):
847 # These exceptions are not strictly errors. Letting
848 # faulthandler display the traceback when they are
849 # raised is likely to result in noise. However, they
850 # may still terminate the process if there is no
851 # handler installed for them (which there typically
852 # is, e.g. for debug messages).
853 for exc in (
854 0x00000000,
855 0x34567890,
856 0x40000000,
857 0x40001000,
858 0x70000000,
859 0x7FFFFFFF,
860 ):
861 output, exitcode = self.get_output(f"""
862 import faulthandler
863 faulthandler.enable()
864 faulthandler._raise_exception(0x{exc:x})
865 """
866 )
867 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200868 # On Windows older than 7 SP1, the actual exception code has
869 # bit 29 cleared.
870 self.assertIn(exitcode,
871 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700872
Victor Stinner937ee9e2018-06-26 02:11:06 +0200873 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200874 def test_disable_windows_exc_handler(self):
875 code = dedent("""
876 import faulthandler
877 faulthandler.enable()
878 faulthandler.disable()
879 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
880 faulthandler._raise_exception(code)
881 """)
882 output, exitcode = self.get_output(code)
883 self.assertEqual(output, [])
884 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100885
Thomas A Caswelle2783352019-08-29 12:30:04 -0400886 def test_cancel_later_without_dump_traceback_later(self):
887 # bpo-37933: Calling cancel_dump_traceback_later()
888 # without dump_traceback_later() must not segfault.
889 code = dedent("""
890 import faulthandler
891 faulthandler.cancel_dump_traceback_later()
892 """)
893 output, exitcode = self.get_output(code)
894 self.assertEqual(output, [])
895 self.assertEqual(exitcode, 0)
896
Victor Stinner024e37a2011-03-31 01:31:06 +0200897
Victor Stinner024e37a2011-03-31 01:31:06 +0200898if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400899 unittest.main()