blob: c6b763a9555ab4b984a6b16c90bf19b5ca957e37 [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 Stinner404cdc52016-03-23 10:39:17 +010092 def check_error(self, code, line_number, fatal_error, *,
93 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020094 fd=None, know_current_thread=True,
95 py_fatal_error=False):
Victor Stinner024e37a2011-03-31 01:31:06 +020096 """
97 Check that the fault handler for fatal errors is enabled and check the
98 traceback from the child process output.
99
100 Raise an error if the output doesn't match the expected format.
101 """
102 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100103 if know_current_thread:
104 header = 'Current thread 0x[0-9a-f]+'
105 else:
106 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200107 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100108 header = 'Stack'
R David Murray44b548d2016-09-08 13:59:53 -0400109 regex = r"""
Gregory P. Smith30e02322018-12-30 18:09:26 -0800110 (?m)^{fatal_error}
Victor Stinner024e37a2011-03-31 01:31:06 +0200111
Victor Stinner861d9ab2016-03-16 22:45:24 +0100112 {header} \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200113 File "<string>", line {lineno} in <module>
114 """
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200115 if py_fatal_error:
116 fatal_error += "\nPython runtime state: initialized"
117 regex = dedent(regex).format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200118 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100119 fatal_error=fatal_error,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200120 header=header).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200121 if other_regex:
122 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100123 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200124 output = '\n'.join(output)
125 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200126 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200127
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100128 def check_fatal_error(self, code, line_number, name_regex, func=None, **kw):
129 if func:
130 name_regex = '%s: %s' % (func, name_regex)
Victor Stinner404cdc52016-03-23 10:39:17 +0100131 fatal_error = 'Fatal Python error: %s' % name_regex
132 self.check_error(code, line_number, fatal_error, **kw)
133
134 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100135 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100136 self.check_error(code, line_number, fatal_error, **kw)
137
Victor Stinner330426c2013-07-03 22:29:42 +0200138 @unittest.skipIf(sys.platform.startswith('aix'),
139 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200140 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200141 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100142 self.check_fatal_error("""
143 import faulthandler
144 faulthandler.enable()
145 faulthandler._read_null()
146 """,
147 3,
148 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
149 '(?:Segmentation fault'
150 '|Bus error'
151 '|Illegal instruction)')
152 else:
153 self.check_windows_exception("""
154 import faulthandler
155 faulthandler.enable()
156 faulthandler._read_null()
157 """,
158 3,
159 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200160
xdegayeef838062017-11-29 11:43:23 +0100161 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200162 def test_sigsegv(self):
163 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200164 import faulthandler
165 faulthandler.enable()
166 faulthandler._sigsegv()
167 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200168 3,
169 'Segmentation fault')
170
Victor Stinner861d9ab2016-03-16 22:45:24 +0100171 def test_fatal_error_c_thread(self):
172 self.check_fatal_error("""
173 import faulthandler
174 faulthandler.enable()
175 faulthandler._fatal_error_c_thread()
176 """,
177 3,
178 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200179 know_current_thread=False,
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100180 func='faulthandler_fatal_error_thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200181 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100182
Victor Stinnerd727e232011-04-01 12:13:55 +0200183 def test_sigabrt(self):
184 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200185 import faulthandler
186 faulthandler.enable()
187 faulthandler._sigabrt()
188 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200189 3,
190 'Aborted')
191
Victor Stinner024e37a2011-03-31 01:31:06 +0200192 @unittest.skipIf(sys.platform == 'win32',
193 "SIGFPE cannot be caught on Windows")
194 def test_sigfpe(self):
195 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200196 import faulthandler
197 faulthandler.enable()
198 faulthandler._sigfpe()
199 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200200 3,
201 'Floating point exception')
202
Victor Stinner56e8c292014-07-21 12:30:22 +0200203 @unittest.skipIf(_testcapi is None, 'need _testcapi')
204 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100205 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200206 def test_sigbus(self):
207 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200208 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200209 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200210
Victor Stinner6d201682014-08-10 19:50:08 +0200211 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800212 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200213 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800214 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200215 'Bus error')
216
Victor Stinner56e8c292014-07-21 12:30:22 +0200217 @unittest.skipIf(_testcapi is None, 'need _testcapi')
218 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100219 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200220 def test_sigill(self):
221 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200222 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200223 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200224
Victor Stinner6d201682014-08-10 19:50:08 +0200225 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800226 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200227 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800228 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200229 'Illegal instruction')
230
Victor Stinnere2320252021-01-18 18:24:29 +0100231 def check_fatal_error_func(self, release_gil):
232 # Test that Py_FatalError() dumps a traceback
233 with support.SuppressCrashReport():
234 self.check_fatal_error(f"""
235 import _testcapi
236 _testcapi.fatal_error(b'xyz', {release_gil})
237 """,
238 2,
239 'xyz',
240 func='test_fatal_error',
241 py_fatal_error=True)
242
Victor Stinner024e37a2011-03-31 01:31:06 +0200243 def test_fatal_error(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100244 self.check_fatal_error_func(False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200245
Victor Stinner57003f82016-03-15 17:23:35 +0100246 def test_fatal_error_without_gil(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100247 self.check_fatal_error_func(True)
Victor Stinner57003f82016-03-15 17:23:35 +0100248
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200249 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200250 "Issue #12868: sigaltstack() doesn't work on "
251 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200252 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
253 'need faulthandler._stack_overflow()')
254 def test_stack_overflow(self):
255 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200256 import faulthandler
257 faulthandler.enable()
258 faulthandler._stack_overflow()
259 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200260 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200261 '(?:Segmentation fault|Bus error)',
262 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200263
xdegayeef838062017-11-29 11:43:23 +0100264 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200265 def test_gil_released(self):
266 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200267 import faulthandler
268 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200269 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200270 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200271 3,
Victor Stinner50838282014-09-30 13:54:14 +0200272 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200273
Gregory P. Smith30e02322018-12-30 18:09:26 -0800274 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800275 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100276 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200277 def test_enable_file(self):
278 with temporary_filename() as filename:
279 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200280 import faulthandler
281 output = open({filename}, 'wb')
282 faulthandler.enable(output)
283 faulthandler._sigsegv()
284 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200285 4,
Victor Stinner56785392013-06-17 23:37:59 +0200286 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200287 filename=filename)
288
Victor Stinnerff2a6612015-03-13 11:01:30 +0100289 @unittest.skipIf(sys.platform == "win32",
290 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800291 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800292 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100293 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100294 def test_enable_fd(self):
295 with tempfile.TemporaryFile('wb+') as fp:
296 fd = fp.fileno()
297 self.check_fatal_error("""
298 import faulthandler
299 import sys
300 faulthandler.enable(%s)
301 faulthandler._sigsegv()
302 """ % fd,
303 4,
304 'Segmentation fault',
305 fd=fd)
306
xdegayeef838062017-11-29 11:43:23 +0100307 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200308 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200310 import faulthandler
311 faulthandler.enable(all_threads=False)
312 faulthandler._sigsegv()
313 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200314 3,
Victor Stinner56785392013-06-17 23:37:59 +0200315 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200316 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200317
xdegayeef838062017-11-29 11:43:23 +0100318 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200319 def test_disable(self):
320 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200321 import faulthandler
322 faulthandler.enable()
323 faulthandler.disable()
324 faulthandler._sigsegv()
325 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200326 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200327 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200328 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200329 self.assertTrue(not_expected not in stderr,
330 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200331 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200332
Victor Stinner250035d2021-01-18 20:47:13 +0100333 @skip_segfault_on_android
334 def test_dump_ext_modules(self):
335 code = """
336 import faulthandler
337 faulthandler.enable()
338 faulthandler._sigsegv()
339 """
340 stderr, exitcode = self.get_output(code)
341 stderr = '\n'.join(stderr)
342 match = re.search('^Extension modules:(.*)$', stderr, re.MULTILINE)
343 if not match:
344 self.fail(f"Cannot find 'Extension modules:' in {stderr!r}")
345 modules = set(match.group(1).strip().split(', '))
346 # Only check for a few extensions, the list doesn't have to be
347 # exhaustive.
348 for ext in ('sys', 'builtins', '_io', 'faulthandler'):
349 self.assertIn(ext, modules)
350
Victor Stinner024e37a2011-03-31 01:31:06 +0200351 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200352 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200353 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200354 # regrtest may replace sys.stderr by io.StringIO object, but
355 # faulthandler.enable() requires that sys.stderr has a fileno()
356 # method
Victor Stinner72488502011-06-29 23:24:31 +0200357 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200358
359 was_enabled = faulthandler.is_enabled()
360 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200361 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200362 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200363 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200364 self.assertFalse(faulthandler.is_enabled())
365 finally:
366 if was_enabled:
367 faulthandler.enable()
368 else:
369 faulthandler.disable()
370 finally:
371 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200372
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200373 def test_disabled_by_default(self):
374 # By default, the module should be disabled
375 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100376 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800377 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100378 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200379 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200380
381 def test_sys_xoptions(self):
382 # Test python -X faulthandler
383 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800384 args = filter(None, (sys.executable,
385 "-E" if sys.flags.ignore_environment else "",
386 "-X", "faulthandler", "-c", code))
387 env = os.environ.copy()
388 env.pop("PYTHONFAULTHANDLER", None)
389 # don't use assert_python_ok() because it always enables faulthandler
390 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200391 self.assertEqual(output.rstrip(), b"True")
392
393 def test_env_var(self):
394 # empty env var
395 code = "import faulthandler; print(faulthandler.is_enabled())"
396 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100397 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200398 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100399 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800400 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200401 output = subprocess.check_output(args, env=env)
402 self.assertEqual(output.rstrip(), b"False")
403
404 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100405 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200406 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100407 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200408 output = subprocess.check_output(args, env=env)
409 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200410
Victor Stinner95bb7142015-03-12 15:32:03 +0100411 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200412 """
413 Explicitly call dump_traceback() function and check its output.
414 Raise an error if the output doesn't match the expected format.
415 """
416 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200417 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200418
Victor Stinner95bb7142015-03-12 15:32:03 +0100419 filename = {filename!r}
420 fd = {fd}
421
Victor Stinner6d201682014-08-10 19:50:08 +0200422 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100423 if filename:
424 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200425 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100426 elif fd is not None:
427 faulthandler.dump_traceback(fd,
428 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200429 else:
430 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200431
Victor Stinner6d201682014-08-10 19:50:08 +0200432 def funcA():
433 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200434
Victor Stinner6d201682014-08-10 19:50:08 +0200435 funcA()
436 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200437 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100438 filename=filename,
439 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200440 )
441 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100442 lineno = 9
443 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300444 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200445 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100446 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200447 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700448 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200449 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100450 ' File "<string>", line 17 in funcA',
451 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200452 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100453 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200454 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200455 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200456
457 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100458 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200459
460 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200461 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100462 self.check_dump_traceback(filename=filename)
463
Victor Stinnerff2a6612015-03-13 11:01:30 +0100464 @unittest.skipIf(sys.platform == "win32",
465 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100466 def test_dump_traceback_fd(self):
467 with tempfile.TemporaryFile('wb+') as fp:
468 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200469
Victor Stinner53386d82012-08-01 19:45:34 +0200470 def test_truncate(self):
471 maxlen = 500
472 func_name = 'x' * (maxlen + 50)
473 truncated = 'x' * maxlen + '...'
474 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200475 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200476
Victor Stinner6d201682014-08-10 19:50:08 +0200477 def {func_name}():
478 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200479
Victor Stinner6d201682014-08-10 19:50:08 +0200480 {func_name}()
481 """
Victor Stinner53386d82012-08-01 19:45:34 +0200482 code = code.format(
483 func_name=func_name,
484 )
485 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700486 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200487 ' File "<string>", line 4 in %s' % truncated,
488 ' File "<string>", line 6 in <module>'
489 ]
490 trace, exitcode = self.get_output(code)
491 self.assertEqual(trace, expected)
492 self.assertEqual(exitcode, 0)
493
Victor Stinner024e37a2011-03-31 01:31:06 +0200494 def check_dump_traceback_threads(self, filename):
495 """
496 Call explicitly dump_traceback(all_threads=True) and check the output.
497 Raise an error if the output doesn't match the expected format.
498 """
499 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200500 import faulthandler
501 from threading import Thread, Event
502 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200503
Victor Stinner6d201682014-08-10 19:50:08 +0200504 def dump():
505 if {filename}:
506 with open({filename}, "wb") as fp:
507 faulthandler.dump_traceback(fp, all_threads=True)
508 else:
509 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200510
Victor Stinner6d201682014-08-10 19:50:08 +0200511 class Waiter(Thread):
512 # avoid blocking if the main thread raises an exception.
513 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200514
Victor Stinner6d201682014-08-10 19:50:08 +0200515 def __init__(self):
516 Thread.__init__(self)
517 self.running = Event()
518 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200519
Victor Stinner6d201682014-08-10 19:50:08 +0200520 def run(self):
521 self.running.set()
522 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200523
Victor Stinner6d201682014-08-10 19:50:08 +0200524 waiter = Waiter()
525 waiter.start()
526 waiter.running.wait()
527 dump()
528 waiter.stop.set()
529 waiter.join()
530 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200531 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200532 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200533 output = '\n'.join(output)
534 if filename:
535 lineno = 8
536 else:
537 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400538 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200539 ^Thread 0x[0-9a-f]+ \(most recent call first\):
540 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
541 ){{1,3}} File "<string>", line 23 in run
542 File ".*threading.py", line [0-9]+ in _bootstrap_inner
543 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200544
Victor Stinner861d9ab2016-03-16 22:45:24 +0100545 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200546 File "<string>", line {lineno} in dump
547 File "<string>", line 28 in <module>$
548 """
549 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200550 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200551 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200552
553 def test_dump_traceback_threads(self):
554 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200555
556 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200557 with temporary_filename() as filename:
558 self.check_dump_traceback_threads(filename)
559
Victor Stinner95bb7142015-03-12 15:32:03 +0100560 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
561 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200562 """
563 Check how many times the traceback is written in timeout x 2.5 seconds,
564 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
565 on repeat and cancel options.
566
567 Raise an error if the output doesn't match the expect format.
568 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200569 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200570 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200571 import faulthandler
572 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100573 import sys
574
575 timeout = {timeout}
576 repeat = {repeat}
577 cancel = {cancel}
578 loops = {loops}
579 filename = {filename!r}
580 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200581
Victor Stinner6d201682014-08-10 19:50:08 +0200582 def func(timeout, repeat, cancel, file, loops):
583 for loop in range(loops):
584 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
585 if cancel:
586 faulthandler.cancel_dump_traceback_later()
587 time.sleep(timeout * 5)
588 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200589
Victor Stinner95bb7142015-03-12 15:32:03 +0100590 if filename:
591 file = open(filename, "wb")
592 elif fd is not None:
593 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200594 else:
595 file = None
596 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100597 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200598 file.close()
599 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200600 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200601 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200602 repeat=repeat,
603 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200604 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100605 filename=filename,
606 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200607 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200608 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200609 trace = '\n'.join(trace)
610
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200611 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200612 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200613 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200614 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700615 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100616 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200617 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200618 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200619 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200620 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200621
Georg Brandldeb92b52012-09-22 08:58:55 +0200622 def test_dump_traceback_later(self):
623 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200624
Georg Brandldeb92b52012-09-22 08:58:55 +0200625 def test_dump_traceback_later_repeat(self):
626 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200627
Georg Brandldeb92b52012-09-22 08:58:55 +0200628 def test_dump_traceback_later_cancel(self):
629 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200630
Georg Brandldeb92b52012-09-22 08:58:55 +0200631 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100632 with temporary_filename() as filename:
633 self.check_dump_traceback_later(filename=filename)
634
Victor Stinnerff2a6612015-03-13 11:01:30 +0100635 @unittest.skipIf(sys.platform == "win32",
636 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100637 def test_dump_traceback_later_fd(self):
638 with tempfile.TemporaryFile('wb+') as fp:
639 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200640
Georg Brandldeb92b52012-09-22 08:58:55 +0200641 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100642 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200643
Victor Stinner024e37a2011-03-31 01:31:06 +0200644 @unittest.skipIf(not hasattr(faulthandler, "register"),
645 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200646 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100647 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200648 """
649 Register a handler displaying the traceback on a user signal. Raise the
650 signal and check the written traceback.
651
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200652 If chain is True, check that the previous signal handler is called.
653
Victor Stinner024e37a2011-03-31 01:31:06 +0200654 Raise an error if the output doesn't match the expected format.
655 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200656 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200657 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200658 import faulthandler
659 import os
660 import signal
661 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200662
Victor Stinner95bb7142015-03-12 15:32:03 +0100663 all_threads = {all_threads}
664 signum = {signum}
665 unregister = {unregister}
666 chain = {chain}
667 filename = {filename!r}
668 fd = {fd}
669
Victor Stinner6d201682014-08-10 19:50:08 +0200670 def func(signum):
671 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200672
Victor Stinner6d201682014-08-10 19:50:08 +0200673 def handler(signum, frame):
674 handler.called = True
675 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200676
Victor Stinner95bb7142015-03-12 15:32:03 +0100677 if filename:
678 file = open(filename, "wb")
679 elif fd is not None:
680 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200681 else:
682 file = None
683 if chain:
684 signal.signal(signum, handler)
685 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100686 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200687 if unregister:
688 faulthandler.unregister(signum)
689 func(signum)
690 if chain and not handler.called:
691 if file is not None:
692 output = file
693 else:
694 output = sys.stderr
695 print("Error: signal handler not called!", file=output)
696 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100697 else:
698 exitcode = 0
699 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200700 file.close()
701 sys.exit(exitcode)
702 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200703 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200704 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200705 signum=signum,
706 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200707 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100708 filename=filename,
709 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200710 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200711 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200712 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200713 if not unregister:
714 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400715 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200716 else:
R David Murray44b548d2016-09-08 13:59:53 -0400717 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100718 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200719 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200720 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200721 self.assertEqual(trace, '')
722 if unregister:
723 self.assertNotEqual(exitcode, 0)
724 else:
725 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200726
727 def test_register(self):
728 self.check_register()
729
Victor Stinnera01ca122011-04-01 12:56:17 +0200730 def test_unregister(self):
731 self.check_register(unregister=True)
732
Victor Stinner024e37a2011-03-31 01:31:06 +0200733 def test_register_file(self):
734 with temporary_filename() as filename:
735 self.check_register(filename=filename)
736
Victor Stinnerff2a6612015-03-13 11:01:30 +0100737 @unittest.skipIf(sys.platform == "win32",
738 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100739 def test_register_fd(self):
740 with tempfile.TemporaryFile('wb+') as fp:
741 self.check_register(fd=fp.fileno())
742
Victor Stinner024e37a2011-03-31 01:31:06 +0200743 def test_register_threads(self):
744 self.check_register(all_threads=True)
745
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200746 def test_register_chain(self):
747 self.check_register(chain=True)
748
Victor Stinnere2d66902014-05-14 17:15:50 +0200749 @contextmanager
750 def check_stderr_none(self):
751 stderr = sys.stderr
752 try:
753 sys.stderr = None
754 with self.assertRaises(RuntimeError) as cm:
755 yield
756 self.assertEqual(str(cm.exception), "sys.stderr is None")
757 finally:
758 sys.stderr = stderr
759
760 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300761 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200762 # instead of just an attribute error: "None has no attribute fileno".
763 with self.check_stderr_none():
764 faulthandler.enable()
765 with self.check_stderr_none():
766 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200767 with self.check_stderr_none():
768 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200769 if hasattr(faulthandler, "register"):
770 with self.check_stderr_none():
771 faulthandler.register(signal.SIGUSR1)
772
Victor Stinner937ee9e2018-06-26 02:11:06 +0200773 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100774 def test_raise_exception(self):
775 for exc, name in (
776 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
777 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
778 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
779 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400780 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100781 import faulthandler
782 faulthandler.enable()
783 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400784 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100785 3,
786 name)
787
Victor Stinner937ee9e2018-06-26 02:11:06 +0200788 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700789 def test_ignore_exception(self):
790 for exc_code in (
791 0xE06D7363, # MSC exception ("Emsc")
792 0xE0434352, # COM Callable Runtime exception ("ECCR")
793 ):
794 code = f"""
795 import faulthandler
796 faulthandler.enable()
797 faulthandler._raise_exception({exc_code})
798 """
799 code = dedent(code)
800 output, exitcode = self.get_output(code)
801 self.assertEqual(output, [])
802 self.assertEqual(exitcode, exc_code)
803
Victor Stinner937ee9e2018-06-26 02:11:06 +0200804 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700805 def test_raise_nonfatal_exception(self):
806 # These exceptions are not strictly errors. Letting
807 # faulthandler display the traceback when they are
808 # raised is likely to result in noise. However, they
809 # may still terminate the process if there is no
810 # handler installed for them (which there typically
811 # is, e.g. for debug messages).
812 for exc in (
813 0x00000000,
814 0x34567890,
815 0x40000000,
816 0x40001000,
817 0x70000000,
818 0x7FFFFFFF,
819 ):
820 output, exitcode = self.get_output(f"""
821 import faulthandler
822 faulthandler.enable()
823 faulthandler._raise_exception(0x{exc:x})
824 """
825 )
826 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200827 # On Windows older than 7 SP1, the actual exception code has
828 # bit 29 cleared.
829 self.assertIn(exitcode,
830 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700831
Victor Stinner937ee9e2018-06-26 02:11:06 +0200832 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200833 def test_disable_windows_exc_handler(self):
834 code = dedent("""
835 import faulthandler
836 faulthandler.enable()
837 faulthandler.disable()
838 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
839 faulthandler._raise_exception(code)
840 """)
841 output, exitcode = self.get_output(code)
842 self.assertEqual(output, [])
843 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100844
Thomas A Caswelle2783352019-08-29 12:30:04 -0400845 def test_cancel_later_without_dump_traceback_later(self):
846 # bpo-37933: Calling cancel_dump_traceback_later()
847 # without dump_traceback_later() must not segfault.
848 code = dedent("""
849 import faulthandler
850 faulthandler.cancel_dump_traceback_later()
851 """)
852 output, exitcode = self.get_output(code)
853 self.assertEqual(output, [])
854 self.assertEqual(exitcode, 0)
855
Victor Stinner024e37a2011-03-31 01:31:06 +0200856
Victor Stinner024e37a2011-03-31 01:31:06 +0200857if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400858 unittest.main()