blob: 648624482e5553c68e6eacfa9f18f466a9ae2508 [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
Victor Stinnerdb584bd2021-01-25 13:24:42 +0100337 import sys
338 # Don't filter stdlib module names
Victor Stinner9852cb32021-01-25 23:12:50 +0100339 sys.stdlib_module_names = frozenset()
Victor Stinner250035d2021-01-18 20:47:13 +0100340 faulthandler.enable()
341 faulthandler._sigsegv()
342 """
343 stderr, exitcode = self.get_output(code)
344 stderr = '\n'.join(stderr)
Victor Stinner66f77ca2021-01-19 23:35:27 +0100345 match = re.search(r'^Extension modules:(.*) \(total: [0-9]+\)$',
346 stderr, re.MULTILINE)
Victor Stinner250035d2021-01-18 20:47:13 +0100347 if not match:
348 self.fail(f"Cannot find 'Extension modules:' in {stderr!r}")
349 modules = set(match.group(1).strip().split(', '))
Victor Stinnerdb584bd2021-01-25 13:24:42 +0100350 for name in ('sys', 'faulthandler'):
351 self.assertIn(name, modules)
Victor Stinner250035d2021-01-18 20:47:13 +0100352
Victor Stinner024e37a2011-03-31 01:31:06 +0200353 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200354 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200355 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200356 # regrtest may replace sys.stderr by io.StringIO object, but
357 # faulthandler.enable() requires that sys.stderr has a fileno()
358 # method
Victor Stinner72488502011-06-29 23:24:31 +0200359 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200360
361 was_enabled = faulthandler.is_enabled()
362 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200363 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200364 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200365 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200366 self.assertFalse(faulthandler.is_enabled())
367 finally:
368 if was_enabled:
369 faulthandler.enable()
370 else:
371 faulthandler.disable()
372 finally:
373 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200374
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200375 def test_disabled_by_default(self):
376 # By default, the module should be disabled
377 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100378 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800379 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100380 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200381 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200382
383 def test_sys_xoptions(self):
384 # Test python -X faulthandler
385 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800386 args = filter(None, (sys.executable,
387 "-E" if sys.flags.ignore_environment else "",
388 "-X", "faulthandler", "-c", code))
389 env = os.environ.copy()
390 env.pop("PYTHONFAULTHANDLER", None)
391 # don't use assert_python_ok() because it always enables faulthandler
392 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200393 self.assertEqual(output.rstrip(), b"True")
394
395 def test_env_var(self):
396 # empty env var
397 code = "import faulthandler; print(faulthandler.is_enabled())"
398 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100399 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200400 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100401 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800402 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200403 output = subprocess.check_output(args, env=env)
404 self.assertEqual(output.rstrip(), b"False")
405
406 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100407 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200408 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100409 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200410 output = subprocess.check_output(args, env=env)
411 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200412
Victor Stinner95bb7142015-03-12 15:32:03 +0100413 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200414 """
415 Explicitly call dump_traceback() function and check its output.
416 Raise an error if the output doesn't match the expected format.
417 """
418 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200419 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200420
Victor Stinner95bb7142015-03-12 15:32:03 +0100421 filename = {filename!r}
422 fd = {fd}
423
Victor Stinner6d201682014-08-10 19:50:08 +0200424 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100425 if filename:
426 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200427 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100428 elif fd is not None:
429 faulthandler.dump_traceback(fd,
430 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200431 else:
432 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200433
Victor Stinner6d201682014-08-10 19:50:08 +0200434 def funcA():
435 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200436
Victor Stinner6d201682014-08-10 19:50:08 +0200437 funcA()
438 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200439 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100440 filename=filename,
441 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200442 )
443 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100444 lineno = 9
445 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300446 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200447 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100448 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200449 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700450 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200451 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100452 ' File "<string>", line 17 in funcA',
453 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200454 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100455 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200456 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200457 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200458
459 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100460 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200461
462 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200463 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100464 self.check_dump_traceback(filename=filename)
465
Victor Stinnerff2a6612015-03-13 11:01:30 +0100466 @unittest.skipIf(sys.platform == "win32",
467 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100468 def test_dump_traceback_fd(self):
469 with tempfile.TemporaryFile('wb+') as fp:
470 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200471
Victor Stinner53386d82012-08-01 19:45:34 +0200472 def test_truncate(self):
473 maxlen = 500
474 func_name = 'x' * (maxlen + 50)
475 truncated = 'x' * maxlen + '...'
476 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200477 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200478
Victor Stinner6d201682014-08-10 19:50:08 +0200479 def {func_name}():
480 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200481
Victor Stinner6d201682014-08-10 19:50:08 +0200482 {func_name}()
483 """
Victor Stinner53386d82012-08-01 19:45:34 +0200484 code = code.format(
485 func_name=func_name,
486 )
487 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700488 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200489 ' File "<string>", line 4 in %s' % truncated,
490 ' File "<string>", line 6 in <module>'
491 ]
492 trace, exitcode = self.get_output(code)
493 self.assertEqual(trace, expected)
494 self.assertEqual(exitcode, 0)
495
Victor Stinner024e37a2011-03-31 01:31:06 +0200496 def check_dump_traceback_threads(self, filename):
497 """
498 Call explicitly dump_traceback(all_threads=True) and check the output.
499 Raise an error if the output doesn't match the expected format.
500 """
501 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200502 import faulthandler
503 from threading import Thread, Event
504 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200505
Victor Stinner6d201682014-08-10 19:50:08 +0200506 def dump():
507 if {filename}:
508 with open({filename}, "wb") as fp:
509 faulthandler.dump_traceback(fp, all_threads=True)
510 else:
511 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200512
Victor Stinner6d201682014-08-10 19:50:08 +0200513 class Waiter(Thread):
514 # avoid blocking if the main thread raises an exception.
515 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200516
Victor Stinner6d201682014-08-10 19:50:08 +0200517 def __init__(self):
518 Thread.__init__(self)
519 self.running = Event()
520 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200521
Victor Stinner6d201682014-08-10 19:50:08 +0200522 def run(self):
523 self.running.set()
524 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200525
Victor Stinner6d201682014-08-10 19:50:08 +0200526 waiter = Waiter()
527 waiter.start()
528 waiter.running.wait()
529 dump()
530 waiter.stop.set()
531 waiter.join()
532 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200533 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200534 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200535 output = '\n'.join(output)
536 if filename:
537 lineno = 8
538 else:
539 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400540 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200541 ^Thread 0x[0-9a-f]+ \(most recent call first\):
542 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
543 ){{1,3}} File "<string>", line 23 in run
544 File ".*threading.py", line [0-9]+ in _bootstrap_inner
545 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200546
Victor Stinner861d9ab2016-03-16 22:45:24 +0100547 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200548 File "<string>", line {lineno} in dump
549 File "<string>", line 28 in <module>$
550 """
551 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200552 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200553 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200554
555 def test_dump_traceback_threads(self):
556 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200557
558 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200559 with temporary_filename() as filename:
560 self.check_dump_traceback_threads(filename)
561
Victor Stinner95bb7142015-03-12 15:32:03 +0100562 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
563 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200564 """
565 Check how many times the traceback is written in timeout x 2.5 seconds,
566 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
567 on repeat and cancel options.
568
569 Raise an error if the output doesn't match the expect format.
570 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200571 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200572 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200573 import faulthandler
574 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100575 import sys
576
577 timeout = {timeout}
578 repeat = {repeat}
579 cancel = {cancel}
580 loops = {loops}
581 filename = {filename!r}
582 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200583
Victor Stinner6d201682014-08-10 19:50:08 +0200584 def func(timeout, repeat, cancel, file, loops):
585 for loop in range(loops):
586 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
587 if cancel:
588 faulthandler.cancel_dump_traceback_later()
589 time.sleep(timeout * 5)
590 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200591
Victor Stinner95bb7142015-03-12 15:32:03 +0100592 if filename:
593 file = open(filename, "wb")
594 elif fd is not None:
595 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200596 else:
597 file = None
598 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100599 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200600 file.close()
601 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200602 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200603 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200604 repeat=repeat,
605 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200606 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100607 filename=filename,
608 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200609 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200610 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200611 trace = '\n'.join(trace)
612
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200613 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200614 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200615 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200616 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700617 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100618 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200619 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200620 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200621 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200622 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200623
Georg Brandldeb92b52012-09-22 08:58:55 +0200624 def test_dump_traceback_later(self):
625 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200626
Georg Brandldeb92b52012-09-22 08:58:55 +0200627 def test_dump_traceback_later_repeat(self):
628 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200629
Georg Brandldeb92b52012-09-22 08:58:55 +0200630 def test_dump_traceback_later_cancel(self):
631 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200632
Georg Brandldeb92b52012-09-22 08:58:55 +0200633 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100634 with temporary_filename() as filename:
635 self.check_dump_traceback_later(filename=filename)
636
Victor Stinnerff2a6612015-03-13 11:01:30 +0100637 @unittest.skipIf(sys.platform == "win32",
638 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100639 def test_dump_traceback_later_fd(self):
640 with tempfile.TemporaryFile('wb+') as fp:
641 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200642
Georg Brandldeb92b52012-09-22 08:58:55 +0200643 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100644 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200645
Victor Stinner024e37a2011-03-31 01:31:06 +0200646 @unittest.skipIf(not hasattr(faulthandler, "register"),
647 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200648 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100649 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200650 """
651 Register a handler displaying the traceback on a user signal. Raise the
652 signal and check the written traceback.
653
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200654 If chain is True, check that the previous signal handler is called.
655
Victor Stinner024e37a2011-03-31 01:31:06 +0200656 Raise an error if the output doesn't match the expected format.
657 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200658 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200659 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200660 import faulthandler
661 import os
662 import signal
663 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200664
Victor Stinner95bb7142015-03-12 15:32:03 +0100665 all_threads = {all_threads}
666 signum = {signum}
667 unregister = {unregister}
668 chain = {chain}
669 filename = {filename!r}
670 fd = {fd}
671
Victor Stinner6d201682014-08-10 19:50:08 +0200672 def func(signum):
673 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200674
Victor Stinner6d201682014-08-10 19:50:08 +0200675 def handler(signum, frame):
676 handler.called = True
677 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200678
Victor Stinner95bb7142015-03-12 15:32:03 +0100679 if filename:
680 file = open(filename, "wb")
681 elif fd is not None:
682 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200683 else:
684 file = None
685 if chain:
686 signal.signal(signum, handler)
687 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100688 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200689 if unregister:
690 faulthandler.unregister(signum)
691 func(signum)
692 if chain and not handler.called:
693 if file is not None:
694 output = file
695 else:
696 output = sys.stderr
697 print("Error: signal handler not called!", file=output)
698 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100699 else:
700 exitcode = 0
701 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200702 file.close()
703 sys.exit(exitcode)
704 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200705 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200706 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200707 signum=signum,
708 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200709 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100710 filename=filename,
711 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200712 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200713 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200714 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200715 if not unregister:
716 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400717 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200718 else:
R David Murray44b548d2016-09-08 13:59:53 -0400719 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100720 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200721 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200722 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200723 self.assertEqual(trace, '')
724 if unregister:
725 self.assertNotEqual(exitcode, 0)
726 else:
727 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200728
729 def test_register(self):
730 self.check_register()
731
Victor Stinnera01ca122011-04-01 12:56:17 +0200732 def test_unregister(self):
733 self.check_register(unregister=True)
734
Victor Stinner024e37a2011-03-31 01:31:06 +0200735 def test_register_file(self):
736 with temporary_filename() as filename:
737 self.check_register(filename=filename)
738
Victor Stinnerff2a6612015-03-13 11:01:30 +0100739 @unittest.skipIf(sys.platform == "win32",
740 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100741 def test_register_fd(self):
742 with tempfile.TemporaryFile('wb+') as fp:
743 self.check_register(fd=fp.fileno())
744
Victor Stinner024e37a2011-03-31 01:31:06 +0200745 def test_register_threads(self):
746 self.check_register(all_threads=True)
747
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200748 def test_register_chain(self):
749 self.check_register(chain=True)
750
Victor Stinnere2d66902014-05-14 17:15:50 +0200751 @contextmanager
752 def check_stderr_none(self):
753 stderr = sys.stderr
754 try:
755 sys.stderr = None
756 with self.assertRaises(RuntimeError) as cm:
757 yield
758 self.assertEqual(str(cm.exception), "sys.stderr is None")
759 finally:
760 sys.stderr = stderr
761
762 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300763 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200764 # instead of just an attribute error: "None has no attribute fileno".
765 with self.check_stderr_none():
766 faulthandler.enable()
767 with self.check_stderr_none():
768 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200769 with self.check_stderr_none():
770 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200771 if hasattr(faulthandler, "register"):
772 with self.check_stderr_none():
773 faulthandler.register(signal.SIGUSR1)
774
Victor Stinner937ee9e2018-06-26 02:11:06 +0200775 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100776 def test_raise_exception(self):
777 for exc, name in (
778 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
779 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
780 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
781 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400782 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100783 import faulthandler
784 faulthandler.enable()
785 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400786 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100787 3,
788 name)
789
Victor Stinner937ee9e2018-06-26 02:11:06 +0200790 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700791 def test_ignore_exception(self):
792 for exc_code in (
793 0xE06D7363, # MSC exception ("Emsc")
794 0xE0434352, # COM Callable Runtime exception ("ECCR")
795 ):
796 code = f"""
797 import faulthandler
798 faulthandler.enable()
799 faulthandler._raise_exception({exc_code})
800 """
801 code = dedent(code)
802 output, exitcode = self.get_output(code)
803 self.assertEqual(output, [])
804 self.assertEqual(exitcode, exc_code)
805
Victor Stinner937ee9e2018-06-26 02:11:06 +0200806 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700807 def test_raise_nonfatal_exception(self):
808 # These exceptions are not strictly errors. Letting
809 # faulthandler display the traceback when they are
810 # raised is likely to result in noise. However, they
811 # may still terminate the process if there is no
812 # handler installed for them (which there typically
813 # is, e.g. for debug messages).
814 for exc in (
815 0x00000000,
816 0x34567890,
817 0x40000000,
818 0x40001000,
819 0x70000000,
820 0x7FFFFFFF,
821 ):
822 output, exitcode = self.get_output(f"""
823 import faulthandler
824 faulthandler.enable()
825 faulthandler._raise_exception(0x{exc:x})
826 """
827 )
828 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200829 # On Windows older than 7 SP1, the actual exception code has
830 # bit 29 cleared.
831 self.assertIn(exitcode,
832 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700833
Victor Stinner937ee9e2018-06-26 02:11:06 +0200834 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200835 def test_disable_windows_exc_handler(self):
836 code = dedent("""
837 import faulthandler
838 faulthandler.enable()
839 faulthandler.disable()
840 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
841 faulthandler._raise_exception(code)
842 """)
843 output, exitcode = self.get_output(code)
844 self.assertEqual(output, [])
845 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100846
Thomas A Caswelle2783352019-08-29 12:30:04 -0400847 def test_cancel_later_without_dump_traceback_later(self):
848 # bpo-37933: Calling cancel_dump_traceback_later()
849 # without dump_traceback_later() must not segfault.
850 code = dedent("""
851 import faulthandler
852 faulthandler.cancel_dump_traceback_later()
853 """)
854 output, exitcode = self.get_output(code)
855 self.assertEqual(output, [])
856 self.assertEqual(exitcode, 0)
857
Victor Stinner024e37a2011-03-31 01:31:06 +0200858
Victor Stinner024e37a2011-03-31 01:31:06 +0200859if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400860 unittest.main()