blob: 24487446f25b3391d4dcdf75d0a854b3acdc59b9 [file] [log] [blame]
Victor Stinner024e37a2011-03-31 01:31:06 +02001from contextlib import contextmanager
Victor Stinnerc790a532011-04-08 13:39:59 +02002import datetime
Victor Stinner024e37a2011-03-31 01:31:06 +02003import faulthandler
Victor Stinner7e32f3a2011-06-29 13:44:05 +02004import os
Victor Stinner024e37a2011-03-31 01:31:06 +02005import signal
6import subprocess
7import sys
Gregory P. Smithb474e672018-12-30 17:05:36 -08008import sysconfig
Berker Peksagce643912015-05-06 06:33:17 +03009from test import support
Victor Stinner937ee9e2018-06-26 02:11:06 +020010from test.support import script_helper, is_android
Victor Stinner024e37a2011-03-31 01:31:06 +020011import tempfile
12import unittest
Victor Stinner6d201682014-08-10 19:50:08 +020013from textwrap import dedent
Victor Stinner024e37a2011-03-31 01:31:06 +020014
Victor Stinnerff4cd882011-04-07 11:50:25 +020015try:
Victor Stinner56e8c292014-07-21 12:30:22 +020016 import _testcapi
17except ImportError:
18 _testcapi = None
Victor Stinnerff4cd882011-04-07 11:50:25 +020019
Victor Stinner44378d42011-04-01 15:37:12 +020020TIMEOUT = 0.5
Victor Stinner937ee9e2018-06-26 02:11:06 +020021MS_WINDOWS = (os.name == 'nt')
Gregory P. Smith30e02322018-12-30 18:09:26 -080022_cflags = sysconfig.get_config_var('CFLAGS') or ''
23_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
24UB_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080025 '-fsanitize=undefined' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080026 '--with-undefined-behavior-sanitizer' in _config_args
Gregory P. Smithb474e672018-12-30 17:05:36 -080027)
Gregory P. Smith30e02322018-12-30 18:09:26 -080028MEMORY_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080029 '-fsanitize=memory' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080030 '--with-memory-sanitizer' in _config_args
31)
32
Victor Stinner44378d42011-04-01 15:37:12 +020033
Victor Stinner301f3f02011-06-01 13:49:12 +020034def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020035 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020036 regex += ' File "<string>", line %s in func\n' % lineno1
37 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020038 if 1 < min_count:
39 return '^' + (regex + '\n') * (min_count - 1) + regex
40 else:
41 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020042
xdegayeef838062017-11-29 11:43:23 +010043def skip_segfault_on_android(test):
44 # Issue #32138: Raising SIGSEGV on Android may not cause a crash.
Victor Stinner937ee9e2018-06-26 02:11:06 +020045 return unittest.skipIf(is_android,
xdegayeef838062017-11-29 11:43:23 +010046 'raising SIGSEGV on Android is unreliable')(test)
47
Victor Stinner024e37a2011-03-31 01:31:06 +020048@contextmanager
49def temporary_filename():
50 filename = tempfile.mktemp()
51 try:
52 yield filename
53 finally:
54 support.unlink(filename)
55
56class FaultHandlerTests(unittest.TestCase):
Victor Stinner95bb7142015-03-12 15:32:03 +010057 def get_output(self, code, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020058 """
59 Run the specified code in Python (in a new child process) and read the
60 output from the standard error or from a file (if filename is set).
61 Return the output lines as a list.
62
63 Strip the reference count from the standard error for Python debug
64 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
65 thread XXX".
66 """
Victor Stinner6d201682014-08-10 19:50:08 +020067 code = dedent(code).strip()
Victor Stinner95bb7142015-03-12 15:32:03 +010068 pass_fds = []
69 if fd is not None:
70 pass_fds.append(fd)
Antoine Pitrou77e904e2013-10-08 23:04:32 +020071 with support.SuppressCrashReport():
Victor Stinner95bb7142015-03-12 15:32:03 +010072 process = script_helper.spawn_python('-c', code, pass_fds=pass_fds)
Victor Stinner861d9ab2016-03-16 22:45:24 +010073 with process:
74 stdout, stderr = process.communicate()
75 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020076 output = support.strip_python_stderr(stdout)
77 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020078 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020079 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020080 with open(filename, "rb") as fp:
81 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020082 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010083 elif fd is not None:
84 self.assertEqual(output, '')
85 os.lseek(fd, os.SEEK_SET, 0)
86 with open(fd, "rb", closefd=False) as fp:
87 output = fp.read()
88 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020089 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020090
Victor Stinner404cdc52016-03-23 10:39:17 +010091 def check_error(self, code, line_number, fatal_error, *,
92 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020093 fd=None, know_current_thread=True,
94 py_fatal_error=False):
Victor Stinner024e37a2011-03-31 01:31:06 +020095 """
96 Check that the fault handler for fatal errors is enabled and check the
97 traceback from the child process output.
98
99 Raise an error if the output doesn't match the expected format.
100 """
101 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100102 if know_current_thread:
103 header = 'Current thread 0x[0-9a-f]+'
104 else:
105 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200106 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100107 header = 'Stack'
R David Murray44b548d2016-09-08 13:59:53 -0400108 regex = r"""
Gregory P. Smith30e02322018-12-30 18:09:26 -0800109 (?m)^{fatal_error}
Victor Stinner024e37a2011-03-31 01:31:06 +0200110
Victor Stinner861d9ab2016-03-16 22:45:24 +0100111 {header} \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200112 File "<string>", line {lineno} in <module>
113 """
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200114 if py_fatal_error:
115 fatal_error += "\nPython runtime state: initialized"
116 regex = dedent(regex).format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200117 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100118 fatal_error=fatal_error,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200119 header=header).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200120 if other_regex:
121 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100122 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200123 output = '\n'.join(output)
124 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200125 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200126
Victor Stinner404cdc52016-03-23 10:39:17 +0100127 def check_fatal_error(self, code, line_number, name_regex, **kw):
128 fatal_error = 'Fatal Python error: %s' % name_regex
129 self.check_error(code, line_number, fatal_error, **kw)
130
131 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100132 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100133 self.check_error(code, line_number, fatal_error, **kw)
134
Victor Stinner330426c2013-07-03 22:29:42 +0200135 @unittest.skipIf(sys.platform.startswith('aix'),
136 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200137 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200138 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100139 self.check_fatal_error("""
140 import faulthandler
141 faulthandler.enable()
142 faulthandler._read_null()
143 """,
144 3,
145 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
146 '(?:Segmentation fault'
147 '|Bus error'
148 '|Illegal instruction)')
149 else:
150 self.check_windows_exception("""
151 import faulthandler
152 faulthandler.enable()
153 faulthandler._read_null()
154 """,
155 3,
156 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200157
xdegayeef838062017-11-29 11:43:23 +0100158 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200159 def test_sigsegv(self):
160 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200161 import faulthandler
162 faulthandler.enable()
163 faulthandler._sigsegv()
164 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200165 3,
166 'Segmentation fault')
167
Victor Stinner861d9ab2016-03-16 22:45:24 +0100168 def test_fatal_error_c_thread(self):
169 self.check_fatal_error("""
170 import faulthandler
171 faulthandler.enable()
172 faulthandler._fatal_error_c_thread()
173 """,
174 3,
175 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200176 know_current_thread=False,
177 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100178
Victor Stinnerd727e232011-04-01 12:13:55 +0200179 def test_sigabrt(self):
180 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200181 import faulthandler
182 faulthandler.enable()
183 faulthandler._sigabrt()
184 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200185 3,
186 'Aborted')
187
Victor Stinner024e37a2011-03-31 01:31:06 +0200188 @unittest.skipIf(sys.platform == 'win32',
189 "SIGFPE cannot be caught on Windows")
190 def test_sigfpe(self):
191 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200192 import faulthandler
193 faulthandler.enable()
194 faulthandler._sigfpe()
195 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200196 3,
197 'Floating point exception')
198
Victor Stinner56e8c292014-07-21 12:30:22 +0200199 @unittest.skipIf(_testcapi is None, 'need _testcapi')
200 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100201 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200202 def test_sigbus(self):
203 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200204 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200205 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200206
Victor Stinner6d201682014-08-10 19:50:08 +0200207 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800208 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200209 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800210 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200211 'Bus error')
212
Victor Stinner56e8c292014-07-21 12:30:22 +0200213 @unittest.skipIf(_testcapi is None, 'need _testcapi')
214 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100215 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200216 def test_sigill(self):
217 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200218 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200219 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200220
Victor Stinner6d201682014-08-10 19:50:08 +0200221 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800222 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200223 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800224 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200225 'Illegal instruction')
226
227 def test_fatal_error(self):
228 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200229 import faulthandler
230 faulthandler._fatal_error(b'xyz')
231 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200232 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200233 'xyz',
234 py_fatal_error=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200235
Victor Stinner57003f82016-03-15 17:23:35 +0100236 def test_fatal_error_without_gil(self):
237 self.check_fatal_error("""
238 import faulthandler
239 faulthandler._fatal_error(b'xyz', True)
240 """,
241 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200242 'xyz',
243 py_fatal_error=True)
Victor Stinner57003f82016-03-15 17:23:35 +0100244
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200245 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200246 "Issue #12868: sigaltstack() doesn't work on "
247 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200248 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
249 'need faulthandler._stack_overflow()')
250 def test_stack_overflow(self):
251 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200252 import faulthandler
253 faulthandler.enable()
254 faulthandler._stack_overflow()
255 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200256 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200257 '(?:Segmentation fault|Bus error)',
258 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200259
xdegayeef838062017-11-29 11:43:23 +0100260 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200261 def test_gil_released(self):
262 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200263 import faulthandler
264 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200265 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200266 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200267 3,
Victor Stinner50838282014-09-30 13:54:14 +0200268 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200269
Gregory P. Smith30e02322018-12-30 18:09:26 -0800270 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800271 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100272 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200273 def test_enable_file(self):
274 with temporary_filename() as filename:
275 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200276 import faulthandler
277 output = open({filename}, 'wb')
278 faulthandler.enable(output)
279 faulthandler._sigsegv()
280 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200281 4,
Victor Stinner56785392013-06-17 23:37:59 +0200282 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200283 filename=filename)
284
Victor Stinnerff2a6612015-03-13 11:01:30 +0100285 @unittest.skipIf(sys.platform == "win32",
286 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800287 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800288 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100289 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100290 def test_enable_fd(self):
291 with tempfile.TemporaryFile('wb+') as fp:
292 fd = fp.fileno()
293 self.check_fatal_error("""
294 import faulthandler
295 import sys
296 faulthandler.enable(%s)
297 faulthandler._sigsegv()
298 """ % fd,
299 4,
300 'Segmentation fault',
301 fd=fd)
302
xdegayeef838062017-11-29 11:43:23 +0100303 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200304 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200305 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200306 import faulthandler
307 faulthandler.enable(all_threads=False)
308 faulthandler._sigsegv()
309 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200310 3,
Victor Stinner56785392013-06-17 23:37:59 +0200311 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200312 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200313
xdegayeef838062017-11-29 11:43:23 +0100314 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200315 def test_disable(self):
316 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200317 import faulthandler
318 faulthandler.enable()
319 faulthandler.disable()
320 faulthandler._sigsegv()
321 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200322 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200323 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200324 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200325 self.assertTrue(not_expected not in stderr,
326 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200327 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200328
329 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200330 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200331 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200332 # regrtest may replace sys.stderr by io.StringIO object, but
333 # faulthandler.enable() requires that sys.stderr has a fileno()
334 # method
Victor Stinner72488502011-06-29 23:24:31 +0200335 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200336
337 was_enabled = faulthandler.is_enabled()
338 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200339 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200340 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200341 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200342 self.assertFalse(faulthandler.is_enabled())
343 finally:
344 if was_enabled:
345 faulthandler.enable()
346 else:
347 faulthandler.disable()
348 finally:
349 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200350
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200351 def test_disabled_by_default(self):
352 # By default, the module should be disabled
353 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100354 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800355 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100356 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200357 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200358
359 def test_sys_xoptions(self):
360 # Test python -X faulthandler
361 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800362 args = filter(None, (sys.executable,
363 "-E" if sys.flags.ignore_environment else "",
364 "-X", "faulthandler", "-c", code))
365 env = os.environ.copy()
366 env.pop("PYTHONFAULTHANDLER", None)
367 # don't use assert_python_ok() because it always enables faulthandler
368 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200369 self.assertEqual(output.rstrip(), b"True")
370
371 def test_env_var(self):
372 # empty env var
373 code = "import faulthandler; print(faulthandler.is_enabled())"
374 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100375 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200376 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100377 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800378 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200379 output = subprocess.check_output(args, env=env)
380 self.assertEqual(output.rstrip(), b"False")
381
382 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100383 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200384 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100385 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200386 output = subprocess.check_output(args, env=env)
387 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200388
Victor Stinner95bb7142015-03-12 15:32:03 +0100389 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200390 """
391 Explicitly call dump_traceback() function and check its output.
392 Raise an error if the output doesn't match the expected format.
393 """
394 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200395 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200396
Victor Stinner95bb7142015-03-12 15:32:03 +0100397 filename = {filename!r}
398 fd = {fd}
399
Victor Stinner6d201682014-08-10 19:50:08 +0200400 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100401 if filename:
402 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200403 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100404 elif fd is not None:
405 faulthandler.dump_traceback(fd,
406 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200407 else:
408 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200409
Victor Stinner6d201682014-08-10 19:50:08 +0200410 def funcA():
411 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200412
Victor Stinner6d201682014-08-10 19:50:08 +0200413 funcA()
414 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200415 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100416 filename=filename,
417 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200418 )
419 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100420 lineno = 9
421 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300422 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200423 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100424 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200425 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700426 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200427 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100428 ' File "<string>", line 17 in funcA',
429 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200430 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100431 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200432 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200433 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200434
435 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100436 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200437
438 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200439 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100440 self.check_dump_traceback(filename=filename)
441
Victor Stinnerff2a6612015-03-13 11:01:30 +0100442 @unittest.skipIf(sys.platform == "win32",
443 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100444 def test_dump_traceback_fd(self):
445 with tempfile.TemporaryFile('wb+') as fp:
446 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200447
Victor Stinner53386d82012-08-01 19:45:34 +0200448 def test_truncate(self):
449 maxlen = 500
450 func_name = 'x' * (maxlen + 50)
451 truncated = 'x' * maxlen + '...'
452 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200453 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200454
Victor Stinner6d201682014-08-10 19:50:08 +0200455 def {func_name}():
456 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200457
Victor Stinner6d201682014-08-10 19:50:08 +0200458 {func_name}()
459 """
Victor Stinner53386d82012-08-01 19:45:34 +0200460 code = code.format(
461 func_name=func_name,
462 )
463 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700464 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200465 ' File "<string>", line 4 in %s' % truncated,
466 ' File "<string>", line 6 in <module>'
467 ]
468 trace, exitcode = self.get_output(code)
469 self.assertEqual(trace, expected)
470 self.assertEqual(exitcode, 0)
471
Victor Stinner024e37a2011-03-31 01:31:06 +0200472 def check_dump_traceback_threads(self, filename):
473 """
474 Call explicitly dump_traceback(all_threads=True) and check the output.
475 Raise an error if the output doesn't match the expected format.
476 """
477 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200478 import faulthandler
479 from threading import Thread, Event
480 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200481
Victor Stinner6d201682014-08-10 19:50:08 +0200482 def dump():
483 if {filename}:
484 with open({filename}, "wb") as fp:
485 faulthandler.dump_traceback(fp, all_threads=True)
486 else:
487 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200488
Victor Stinner6d201682014-08-10 19:50:08 +0200489 class Waiter(Thread):
490 # avoid blocking if the main thread raises an exception.
491 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200492
Victor Stinner6d201682014-08-10 19:50:08 +0200493 def __init__(self):
494 Thread.__init__(self)
495 self.running = Event()
496 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200497
Victor Stinner6d201682014-08-10 19:50:08 +0200498 def run(self):
499 self.running.set()
500 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200501
Victor Stinner6d201682014-08-10 19:50:08 +0200502 waiter = Waiter()
503 waiter.start()
504 waiter.running.wait()
505 dump()
506 waiter.stop.set()
507 waiter.join()
508 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200509 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200510 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200511 output = '\n'.join(output)
512 if filename:
513 lineno = 8
514 else:
515 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400516 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200517 ^Thread 0x[0-9a-f]+ \(most recent call first\):
518 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
519 ){{1,3}} File "<string>", line 23 in run
520 File ".*threading.py", line [0-9]+ in _bootstrap_inner
521 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200522
Victor Stinner861d9ab2016-03-16 22:45:24 +0100523 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200524 File "<string>", line {lineno} in dump
525 File "<string>", line 28 in <module>$
526 """
527 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200528 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200529 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200530
531 def test_dump_traceback_threads(self):
532 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200533
534 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200535 with temporary_filename() as filename:
536 self.check_dump_traceback_threads(filename)
537
Victor Stinner95bb7142015-03-12 15:32:03 +0100538 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
539 'need faulthandler.dump_traceback_later()')
540 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
541 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200542 """
543 Check how many times the traceback is written in timeout x 2.5 seconds,
544 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
545 on repeat and cancel options.
546
547 Raise an error if the output doesn't match the expect format.
548 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200549 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200550 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200551 import faulthandler
552 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100553 import sys
554
555 timeout = {timeout}
556 repeat = {repeat}
557 cancel = {cancel}
558 loops = {loops}
559 filename = {filename!r}
560 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200561
Victor Stinner6d201682014-08-10 19:50:08 +0200562 def func(timeout, repeat, cancel, file, loops):
563 for loop in range(loops):
564 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
565 if cancel:
566 faulthandler.cancel_dump_traceback_later()
567 time.sleep(timeout * 5)
568 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200569
Victor Stinner95bb7142015-03-12 15:32:03 +0100570 if filename:
571 file = open(filename, "wb")
572 elif fd is not None:
573 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200574 else:
575 file = None
576 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100577 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200578 file.close()
579 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200580 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200581 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200582 repeat=repeat,
583 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200584 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100585 filename=filename,
586 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200587 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200588 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200589 trace = '\n'.join(trace)
590
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200591 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200592 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200593 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200594 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700595 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100596 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200597 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200598 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200599 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200600 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200601
Georg Brandldeb92b52012-09-22 08:58:55 +0200602 def test_dump_traceback_later(self):
603 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200604
Georg Brandldeb92b52012-09-22 08:58:55 +0200605 def test_dump_traceback_later_repeat(self):
606 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200607
Georg Brandldeb92b52012-09-22 08:58:55 +0200608 def test_dump_traceback_later_cancel(self):
609 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200610
Georg Brandldeb92b52012-09-22 08:58:55 +0200611 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100612 with temporary_filename() as filename:
613 self.check_dump_traceback_later(filename=filename)
614
Victor Stinnerff2a6612015-03-13 11:01:30 +0100615 @unittest.skipIf(sys.platform == "win32",
616 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100617 def test_dump_traceback_later_fd(self):
618 with tempfile.TemporaryFile('wb+') as fp:
619 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200620
Georg Brandldeb92b52012-09-22 08:58:55 +0200621 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100622 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200623
Victor Stinner024e37a2011-03-31 01:31:06 +0200624 @unittest.skipIf(not hasattr(faulthandler, "register"),
625 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200626 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100627 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200628 """
629 Register a handler displaying the traceback on a user signal. Raise the
630 signal and check the written traceback.
631
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200632 If chain is True, check that the previous signal handler is called.
633
Victor Stinner024e37a2011-03-31 01:31:06 +0200634 Raise an error if the output doesn't match the expected format.
635 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200636 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200637 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200638 import faulthandler
639 import os
640 import signal
641 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200642
Victor Stinner95bb7142015-03-12 15:32:03 +0100643 all_threads = {all_threads}
644 signum = {signum}
645 unregister = {unregister}
646 chain = {chain}
647 filename = {filename!r}
648 fd = {fd}
649
Victor Stinner6d201682014-08-10 19:50:08 +0200650 def func(signum):
651 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200652
Victor Stinner6d201682014-08-10 19:50:08 +0200653 def handler(signum, frame):
654 handler.called = True
655 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200656
Victor Stinner95bb7142015-03-12 15:32:03 +0100657 if filename:
658 file = open(filename, "wb")
659 elif fd is not None:
660 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200661 else:
662 file = None
663 if chain:
664 signal.signal(signum, handler)
665 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100666 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200667 if unregister:
668 faulthandler.unregister(signum)
669 func(signum)
670 if chain and not handler.called:
671 if file is not None:
672 output = file
673 else:
674 output = sys.stderr
675 print("Error: signal handler not called!", file=output)
676 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100677 else:
678 exitcode = 0
679 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200680 file.close()
681 sys.exit(exitcode)
682 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200683 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200684 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200685 signum=signum,
686 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200687 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100688 filename=filename,
689 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200690 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200691 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200692 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200693 if not unregister:
694 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400695 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200696 else:
R David Murray44b548d2016-09-08 13:59:53 -0400697 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100698 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200699 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200700 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200701 self.assertEqual(trace, '')
702 if unregister:
703 self.assertNotEqual(exitcode, 0)
704 else:
705 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200706
707 def test_register(self):
708 self.check_register()
709
Victor Stinnera01ca122011-04-01 12:56:17 +0200710 def test_unregister(self):
711 self.check_register(unregister=True)
712
Victor Stinner024e37a2011-03-31 01:31:06 +0200713 def test_register_file(self):
714 with temporary_filename() as filename:
715 self.check_register(filename=filename)
716
Victor Stinnerff2a6612015-03-13 11:01:30 +0100717 @unittest.skipIf(sys.platform == "win32",
718 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100719 def test_register_fd(self):
720 with tempfile.TemporaryFile('wb+') as fp:
721 self.check_register(fd=fp.fileno())
722
Victor Stinner024e37a2011-03-31 01:31:06 +0200723 def test_register_threads(self):
724 self.check_register(all_threads=True)
725
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200726 def test_register_chain(self):
727 self.check_register(chain=True)
728
Victor Stinnere2d66902014-05-14 17:15:50 +0200729 @contextmanager
730 def check_stderr_none(self):
731 stderr = sys.stderr
732 try:
733 sys.stderr = None
734 with self.assertRaises(RuntimeError) as cm:
735 yield
736 self.assertEqual(str(cm.exception), "sys.stderr is None")
737 finally:
738 sys.stderr = stderr
739
740 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300741 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200742 # instead of just an attribute error: "None has no attribute fileno".
743 with self.check_stderr_none():
744 faulthandler.enable()
745 with self.check_stderr_none():
746 faulthandler.dump_traceback()
747 if hasattr(faulthandler, 'dump_traceback_later'):
748 with self.check_stderr_none():
749 faulthandler.dump_traceback_later(1e-3)
750 if hasattr(faulthandler, "register"):
751 with self.check_stderr_none():
752 faulthandler.register(signal.SIGUSR1)
753
Victor Stinner937ee9e2018-06-26 02:11:06 +0200754 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100755 def test_raise_exception(self):
756 for exc, name in (
757 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
758 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
759 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
760 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400761 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100762 import faulthandler
763 faulthandler.enable()
764 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400765 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100766 3,
767 name)
768
Victor Stinner937ee9e2018-06-26 02:11:06 +0200769 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700770 def test_ignore_exception(self):
771 for exc_code in (
772 0xE06D7363, # MSC exception ("Emsc")
773 0xE0434352, # COM Callable Runtime exception ("ECCR")
774 ):
775 code = f"""
776 import faulthandler
777 faulthandler.enable()
778 faulthandler._raise_exception({exc_code})
779 """
780 code = dedent(code)
781 output, exitcode = self.get_output(code)
782 self.assertEqual(output, [])
783 self.assertEqual(exitcode, exc_code)
784
Victor Stinner937ee9e2018-06-26 02:11:06 +0200785 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700786 def test_raise_nonfatal_exception(self):
787 # These exceptions are not strictly errors. Letting
788 # faulthandler display the traceback when they are
789 # raised is likely to result in noise. However, they
790 # may still terminate the process if there is no
791 # handler installed for them (which there typically
792 # is, e.g. for debug messages).
793 for exc in (
794 0x00000000,
795 0x34567890,
796 0x40000000,
797 0x40001000,
798 0x70000000,
799 0x7FFFFFFF,
800 ):
801 output, exitcode = self.get_output(f"""
802 import faulthandler
803 faulthandler.enable()
804 faulthandler._raise_exception(0x{exc:x})
805 """
806 )
807 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200808 # On Windows older than 7 SP1, the actual exception code has
809 # bit 29 cleared.
810 self.assertIn(exitcode,
811 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700812
Victor Stinner937ee9e2018-06-26 02:11:06 +0200813 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200814 def test_disable_windows_exc_handler(self):
815 code = dedent("""
816 import faulthandler
817 faulthandler.enable()
818 faulthandler.disable()
819 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
820 faulthandler._raise_exception(code)
821 """)
822 output, exitcode = self.get_output(code)
823 self.assertEqual(output, [])
824 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100825
Thomas A Caswelle2783352019-08-29 12:30:04 -0400826 def test_cancel_later_without_dump_traceback_later(self):
827 # bpo-37933: Calling cancel_dump_traceback_later()
828 # without dump_traceback_later() must not segfault.
829 code = dedent("""
830 import faulthandler
831 faulthandler.cancel_dump_traceback_later()
832 """)
833 output, exitcode = self.get_output(code)
834 self.assertEqual(output, [])
835 self.assertEqual(exitcode, 0)
836
Victor Stinner024e37a2011-03-31 01:31:06 +0200837
Victor Stinner024e37a2011-03-31 01:31:06 +0200838if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400839 unittest.main()