blob: ac8cf4686bf8cac16e1c8bc9145f2bee089d43d0 [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:
Victor Stinner6cac1132019-12-08 08:38:16 +010074 output, stderr = process.communicate()
Victor Stinner861d9ab2016-03-16 22:45:24 +010075 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020076 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020077 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020078 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020079 with open(filename, "rb") as fp:
80 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020081 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010082 elif fd is not None:
83 self.assertEqual(output, '')
84 os.lseek(fd, os.SEEK_SET, 0)
85 with open(fd, "rb", closefd=False) as fp:
86 output = fp.read()
87 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020088 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020089
Victor Stinner404cdc52016-03-23 10:39:17 +010090 def check_error(self, code, line_number, fatal_error, *,
91 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020092 fd=None, know_current_thread=True,
93 py_fatal_error=False):
Victor Stinner024e37a2011-03-31 01:31:06 +020094 """
95 Check that the fault handler for fatal errors is enabled and check the
96 traceback from the child process output.
97
98 Raise an error if the output doesn't match the expected format.
99 """
100 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100101 if know_current_thread:
102 header = 'Current thread 0x[0-9a-f]+'
103 else:
104 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200105 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100106 header = 'Stack'
R David Murray44b548d2016-09-08 13:59:53 -0400107 regex = r"""
Gregory P. Smith30e02322018-12-30 18:09:26 -0800108 (?m)^{fatal_error}
Victor Stinner024e37a2011-03-31 01:31:06 +0200109
Victor Stinner861d9ab2016-03-16 22:45:24 +0100110 {header} \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200111 File "<string>", line {lineno} in <module>
112 """
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200113 if py_fatal_error:
114 fatal_error += "\nPython runtime state: initialized"
115 regex = dedent(regex).format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200116 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100117 fatal_error=fatal_error,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200118 header=header).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200119 if other_regex:
120 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100121 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200122 output = '\n'.join(output)
123 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200124 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200125
Victor Stinner404cdc52016-03-23 10:39:17 +0100126 def check_fatal_error(self, code, line_number, name_regex, **kw):
127 fatal_error = 'Fatal Python error: %s' % name_regex
128 self.check_error(code, line_number, fatal_error, **kw)
129
130 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100131 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100132 self.check_error(code, line_number, fatal_error, **kw)
133
Victor Stinner330426c2013-07-03 22:29:42 +0200134 @unittest.skipIf(sys.platform.startswith('aix'),
135 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200136 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200137 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100138 self.check_fatal_error("""
139 import faulthandler
140 faulthandler.enable()
141 faulthandler._read_null()
142 """,
143 3,
144 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
145 '(?:Segmentation fault'
146 '|Bus error'
147 '|Illegal instruction)')
148 else:
149 self.check_windows_exception("""
150 import faulthandler
151 faulthandler.enable()
152 faulthandler._read_null()
153 """,
154 3,
155 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200156
xdegayeef838062017-11-29 11:43:23 +0100157 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200158 def test_sigsegv(self):
159 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200160 import faulthandler
161 faulthandler.enable()
162 faulthandler._sigsegv()
163 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200164 3,
165 'Segmentation fault')
166
Victor Stinner861d9ab2016-03-16 22:45:24 +0100167 def test_fatal_error_c_thread(self):
168 self.check_fatal_error("""
169 import faulthandler
170 faulthandler.enable()
171 faulthandler._fatal_error_c_thread()
172 """,
173 3,
174 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200175 know_current_thread=False,
176 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100177
Victor Stinnerd727e232011-04-01 12:13:55 +0200178 def test_sigabrt(self):
179 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200180 import faulthandler
181 faulthandler.enable()
182 faulthandler._sigabrt()
183 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200184 3,
185 'Aborted')
186
Victor Stinner024e37a2011-03-31 01:31:06 +0200187 @unittest.skipIf(sys.platform == 'win32',
188 "SIGFPE cannot be caught on Windows")
189 def test_sigfpe(self):
190 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200191 import faulthandler
192 faulthandler.enable()
193 faulthandler._sigfpe()
194 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200195 3,
196 'Floating point exception')
197
Victor Stinner56e8c292014-07-21 12:30:22 +0200198 @unittest.skipIf(_testcapi is None, 'need _testcapi')
199 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100200 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200201 def test_sigbus(self):
202 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200203 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200204 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200205
Victor Stinner6d201682014-08-10 19:50:08 +0200206 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800207 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200208 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800209 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200210 'Bus error')
211
Victor Stinner56e8c292014-07-21 12:30:22 +0200212 @unittest.skipIf(_testcapi is None, 'need _testcapi')
213 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100214 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200215 def test_sigill(self):
216 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200217 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200218 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200219
Victor Stinner6d201682014-08-10 19:50:08 +0200220 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800221 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200222 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800223 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200224 'Illegal instruction')
225
226 def test_fatal_error(self):
227 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200228 import faulthandler
229 faulthandler._fatal_error(b'xyz')
230 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200231 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200232 'xyz',
233 py_fatal_error=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200234
Victor Stinner57003f82016-03-15 17:23:35 +0100235 def test_fatal_error_without_gil(self):
236 self.check_fatal_error("""
237 import faulthandler
238 faulthandler._fatal_error(b'xyz', True)
239 """,
240 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200241 'xyz',
242 py_fatal_error=True)
Victor Stinner57003f82016-03-15 17:23:35 +0100243
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200244 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200245 "Issue #12868: sigaltstack() doesn't work on "
246 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200247 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
248 'need faulthandler._stack_overflow()')
249 def test_stack_overflow(self):
250 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200251 import faulthandler
252 faulthandler.enable()
253 faulthandler._stack_overflow()
254 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200255 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200256 '(?:Segmentation fault|Bus error)',
257 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200258
xdegayeef838062017-11-29 11:43:23 +0100259 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200260 def test_gil_released(self):
261 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200262 import faulthandler
263 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200264 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200265 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200266 3,
Victor Stinner50838282014-09-30 13:54:14 +0200267 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200268
Gregory P. Smith30e02322018-12-30 18:09:26 -0800269 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800270 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100271 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200272 def test_enable_file(self):
273 with temporary_filename() as filename:
274 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200275 import faulthandler
276 output = open({filename}, 'wb')
277 faulthandler.enable(output)
278 faulthandler._sigsegv()
279 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200280 4,
Victor Stinner56785392013-06-17 23:37:59 +0200281 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200282 filename=filename)
283
Victor Stinnerff2a6612015-03-13 11:01:30 +0100284 @unittest.skipIf(sys.platform == "win32",
285 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800286 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800287 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100288 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100289 def test_enable_fd(self):
290 with tempfile.TemporaryFile('wb+') as fp:
291 fd = fp.fileno()
292 self.check_fatal_error("""
293 import faulthandler
294 import sys
295 faulthandler.enable(%s)
296 faulthandler._sigsegv()
297 """ % fd,
298 4,
299 'Segmentation fault',
300 fd=fd)
301
xdegayeef838062017-11-29 11:43:23 +0100302 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200303 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200304 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200305 import faulthandler
306 faulthandler.enable(all_threads=False)
307 faulthandler._sigsegv()
308 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 3,
Victor Stinner56785392013-06-17 23:37:59 +0200310 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200311 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200312
xdegayeef838062017-11-29 11:43:23 +0100313 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200314 def test_disable(self):
315 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200316 import faulthandler
317 faulthandler.enable()
318 faulthandler.disable()
319 faulthandler._sigsegv()
320 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200321 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200322 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200323 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200324 self.assertTrue(not_expected not in stderr,
325 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200326 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200327
328 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200329 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200330 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200331 # regrtest may replace sys.stderr by io.StringIO object, but
332 # faulthandler.enable() requires that sys.stderr has a fileno()
333 # method
Victor Stinner72488502011-06-29 23:24:31 +0200334 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200335
336 was_enabled = faulthandler.is_enabled()
337 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200338 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200339 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200340 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200341 self.assertFalse(faulthandler.is_enabled())
342 finally:
343 if was_enabled:
344 faulthandler.enable()
345 else:
346 faulthandler.disable()
347 finally:
348 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200349
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200350 def test_disabled_by_default(self):
351 # By default, the module should be disabled
352 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100353 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800354 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100355 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200356 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200357
358 def test_sys_xoptions(self):
359 # Test python -X faulthandler
360 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800361 args = filter(None, (sys.executable,
362 "-E" if sys.flags.ignore_environment else "",
363 "-X", "faulthandler", "-c", code))
364 env = os.environ.copy()
365 env.pop("PYTHONFAULTHANDLER", None)
366 # don't use assert_python_ok() because it always enables faulthandler
367 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200368 self.assertEqual(output.rstrip(), b"True")
369
370 def test_env_var(self):
371 # empty env var
372 code = "import faulthandler; print(faulthandler.is_enabled())"
373 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100374 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200375 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100376 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800377 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200378 output = subprocess.check_output(args, env=env)
379 self.assertEqual(output.rstrip(), b"False")
380
381 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100382 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200383 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100384 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200385 output = subprocess.check_output(args, env=env)
386 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200387
Victor Stinner95bb7142015-03-12 15:32:03 +0100388 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200389 """
390 Explicitly call dump_traceback() function and check its output.
391 Raise an error if the output doesn't match the expected format.
392 """
393 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200394 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200395
Victor Stinner95bb7142015-03-12 15:32:03 +0100396 filename = {filename!r}
397 fd = {fd}
398
Victor Stinner6d201682014-08-10 19:50:08 +0200399 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100400 if filename:
401 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200402 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100403 elif fd is not None:
404 faulthandler.dump_traceback(fd,
405 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200406 else:
407 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200408
Victor Stinner6d201682014-08-10 19:50:08 +0200409 def funcA():
410 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200411
Victor Stinner6d201682014-08-10 19:50:08 +0200412 funcA()
413 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200414 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100415 filename=filename,
416 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200417 )
418 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100419 lineno = 9
420 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300421 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200422 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100423 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200424 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700425 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200426 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100427 ' File "<string>", line 17 in funcA',
428 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200429 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100430 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200431 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200432 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200433
434 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100435 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200436
437 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200438 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100439 self.check_dump_traceback(filename=filename)
440
Victor Stinnerff2a6612015-03-13 11:01:30 +0100441 @unittest.skipIf(sys.platform == "win32",
442 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100443 def test_dump_traceback_fd(self):
444 with tempfile.TemporaryFile('wb+') as fp:
445 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200446
Victor Stinner53386d82012-08-01 19:45:34 +0200447 def test_truncate(self):
448 maxlen = 500
449 func_name = 'x' * (maxlen + 50)
450 truncated = 'x' * maxlen + '...'
451 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200452 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200453
Victor Stinner6d201682014-08-10 19:50:08 +0200454 def {func_name}():
455 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200456
Victor Stinner6d201682014-08-10 19:50:08 +0200457 {func_name}()
458 """
Victor Stinner53386d82012-08-01 19:45:34 +0200459 code = code.format(
460 func_name=func_name,
461 )
462 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700463 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200464 ' File "<string>", line 4 in %s' % truncated,
465 ' File "<string>", line 6 in <module>'
466 ]
467 trace, exitcode = self.get_output(code)
468 self.assertEqual(trace, expected)
469 self.assertEqual(exitcode, 0)
470
Victor Stinner024e37a2011-03-31 01:31:06 +0200471 def check_dump_traceback_threads(self, filename):
472 """
473 Call explicitly dump_traceback(all_threads=True) and check the output.
474 Raise an error if the output doesn't match the expected format.
475 """
476 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200477 import faulthandler
478 from threading import Thread, Event
479 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200480
Victor Stinner6d201682014-08-10 19:50:08 +0200481 def dump():
482 if {filename}:
483 with open({filename}, "wb") as fp:
484 faulthandler.dump_traceback(fp, all_threads=True)
485 else:
486 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200487
Victor Stinner6d201682014-08-10 19:50:08 +0200488 class Waiter(Thread):
489 # avoid blocking if the main thread raises an exception.
490 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200491
Victor Stinner6d201682014-08-10 19:50:08 +0200492 def __init__(self):
493 Thread.__init__(self)
494 self.running = Event()
495 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200496
Victor Stinner6d201682014-08-10 19:50:08 +0200497 def run(self):
498 self.running.set()
499 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200500
Victor Stinner6d201682014-08-10 19:50:08 +0200501 waiter = Waiter()
502 waiter.start()
503 waiter.running.wait()
504 dump()
505 waiter.stop.set()
506 waiter.join()
507 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200508 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200509 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200510 output = '\n'.join(output)
511 if filename:
512 lineno = 8
513 else:
514 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400515 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200516 ^Thread 0x[0-9a-f]+ \(most recent call first\):
517 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
518 ){{1,3}} File "<string>", line 23 in run
519 File ".*threading.py", line [0-9]+ in _bootstrap_inner
520 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200521
Victor Stinner861d9ab2016-03-16 22:45:24 +0100522 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200523 File "<string>", line {lineno} in dump
524 File "<string>", line 28 in <module>$
525 """
526 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200527 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200528 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200529
530 def test_dump_traceback_threads(self):
531 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200532
533 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200534 with temporary_filename() as filename:
535 self.check_dump_traceback_threads(filename)
536
Victor Stinner95bb7142015-03-12 15:32:03 +0100537 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
538 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200539 """
540 Check how many times the traceback is written in timeout x 2.5 seconds,
541 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
542 on repeat and cancel options.
543
544 Raise an error if the output doesn't match the expect format.
545 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200546 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200547 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200548 import faulthandler
549 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100550 import sys
551
552 timeout = {timeout}
553 repeat = {repeat}
554 cancel = {cancel}
555 loops = {loops}
556 filename = {filename!r}
557 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200558
Victor Stinner6d201682014-08-10 19:50:08 +0200559 def func(timeout, repeat, cancel, file, loops):
560 for loop in range(loops):
561 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
562 if cancel:
563 faulthandler.cancel_dump_traceback_later()
564 time.sleep(timeout * 5)
565 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200566
Victor Stinner95bb7142015-03-12 15:32:03 +0100567 if filename:
568 file = open(filename, "wb")
569 elif fd is not None:
570 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200571 else:
572 file = None
573 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100574 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200575 file.close()
576 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200577 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200578 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200579 repeat=repeat,
580 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200581 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100582 filename=filename,
583 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200584 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200585 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200586 trace = '\n'.join(trace)
587
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200588 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200589 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200590 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200591 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700592 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100593 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200594 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200595 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200596 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200597 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200598
Georg Brandldeb92b52012-09-22 08:58:55 +0200599 def test_dump_traceback_later(self):
600 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200601
Georg Brandldeb92b52012-09-22 08:58:55 +0200602 def test_dump_traceback_later_repeat(self):
603 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200604
Georg Brandldeb92b52012-09-22 08:58:55 +0200605 def test_dump_traceback_later_cancel(self):
606 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200607
Georg Brandldeb92b52012-09-22 08:58:55 +0200608 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100609 with temporary_filename() as filename:
610 self.check_dump_traceback_later(filename=filename)
611
Victor Stinnerff2a6612015-03-13 11:01:30 +0100612 @unittest.skipIf(sys.platform == "win32",
613 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100614 def test_dump_traceback_later_fd(self):
615 with tempfile.TemporaryFile('wb+') as fp:
616 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200617
Georg Brandldeb92b52012-09-22 08:58:55 +0200618 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100619 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200620
Victor Stinner024e37a2011-03-31 01:31:06 +0200621 @unittest.skipIf(not hasattr(faulthandler, "register"),
622 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200623 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100624 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200625 """
626 Register a handler displaying the traceback on a user signal. Raise the
627 signal and check the written traceback.
628
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200629 If chain is True, check that the previous signal handler is called.
630
Victor Stinner024e37a2011-03-31 01:31:06 +0200631 Raise an error if the output doesn't match the expected format.
632 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200633 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200634 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200635 import faulthandler
636 import os
637 import signal
638 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200639
Victor Stinner95bb7142015-03-12 15:32:03 +0100640 all_threads = {all_threads}
641 signum = {signum}
642 unregister = {unregister}
643 chain = {chain}
644 filename = {filename!r}
645 fd = {fd}
646
Victor Stinner6d201682014-08-10 19:50:08 +0200647 def func(signum):
648 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200649
Victor Stinner6d201682014-08-10 19:50:08 +0200650 def handler(signum, frame):
651 handler.called = True
652 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200653
Victor Stinner95bb7142015-03-12 15:32:03 +0100654 if filename:
655 file = open(filename, "wb")
656 elif fd is not None:
657 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200658 else:
659 file = None
660 if chain:
661 signal.signal(signum, handler)
662 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100663 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200664 if unregister:
665 faulthandler.unregister(signum)
666 func(signum)
667 if chain and not handler.called:
668 if file is not None:
669 output = file
670 else:
671 output = sys.stderr
672 print("Error: signal handler not called!", file=output)
673 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100674 else:
675 exitcode = 0
676 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200677 file.close()
678 sys.exit(exitcode)
679 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200680 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200681 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200682 signum=signum,
683 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200684 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100685 filename=filename,
686 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200687 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200688 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200689 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200690 if not unregister:
691 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400692 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200693 else:
R David Murray44b548d2016-09-08 13:59:53 -0400694 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100695 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200696 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200697 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200698 self.assertEqual(trace, '')
699 if unregister:
700 self.assertNotEqual(exitcode, 0)
701 else:
702 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200703
704 def test_register(self):
705 self.check_register()
706
Victor Stinnera01ca122011-04-01 12:56:17 +0200707 def test_unregister(self):
708 self.check_register(unregister=True)
709
Victor Stinner024e37a2011-03-31 01:31:06 +0200710 def test_register_file(self):
711 with temporary_filename() as filename:
712 self.check_register(filename=filename)
713
Victor Stinnerff2a6612015-03-13 11:01:30 +0100714 @unittest.skipIf(sys.platform == "win32",
715 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100716 def test_register_fd(self):
717 with tempfile.TemporaryFile('wb+') as fp:
718 self.check_register(fd=fp.fileno())
719
Victor Stinner024e37a2011-03-31 01:31:06 +0200720 def test_register_threads(self):
721 self.check_register(all_threads=True)
722
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200723 def test_register_chain(self):
724 self.check_register(chain=True)
725
Victor Stinnere2d66902014-05-14 17:15:50 +0200726 @contextmanager
727 def check_stderr_none(self):
728 stderr = sys.stderr
729 try:
730 sys.stderr = None
731 with self.assertRaises(RuntimeError) as cm:
732 yield
733 self.assertEqual(str(cm.exception), "sys.stderr is None")
734 finally:
735 sys.stderr = stderr
736
737 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300738 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200739 # instead of just an attribute error: "None has no attribute fileno".
740 with self.check_stderr_none():
741 faulthandler.enable()
742 with self.check_stderr_none():
743 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200744 with self.check_stderr_none():
745 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200746 if hasattr(faulthandler, "register"):
747 with self.check_stderr_none():
748 faulthandler.register(signal.SIGUSR1)
749
Victor Stinner937ee9e2018-06-26 02:11:06 +0200750 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100751 def test_raise_exception(self):
752 for exc, name in (
753 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
754 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
755 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
756 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400757 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100758 import faulthandler
759 faulthandler.enable()
760 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400761 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100762 3,
763 name)
764
Victor Stinner937ee9e2018-06-26 02:11:06 +0200765 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700766 def test_ignore_exception(self):
767 for exc_code in (
768 0xE06D7363, # MSC exception ("Emsc")
769 0xE0434352, # COM Callable Runtime exception ("ECCR")
770 ):
771 code = f"""
772 import faulthandler
773 faulthandler.enable()
774 faulthandler._raise_exception({exc_code})
775 """
776 code = dedent(code)
777 output, exitcode = self.get_output(code)
778 self.assertEqual(output, [])
779 self.assertEqual(exitcode, exc_code)
780
Victor Stinner937ee9e2018-06-26 02:11:06 +0200781 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700782 def test_raise_nonfatal_exception(self):
783 # These exceptions are not strictly errors. Letting
784 # faulthandler display the traceback when they are
785 # raised is likely to result in noise. However, they
786 # may still terminate the process if there is no
787 # handler installed for them (which there typically
788 # is, e.g. for debug messages).
789 for exc in (
790 0x00000000,
791 0x34567890,
792 0x40000000,
793 0x40001000,
794 0x70000000,
795 0x7FFFFFFF,
796 ):
797 output, exitcode = self.get_output(f"""
798 import faulthandler
799 faulthandler.enable()
800 faulthandler._raise_exception(0x{exc:x})
801 """
802 )
803 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200804 # On Windows older than 7 SP1, the actual exception code has
805 # bit 29 cleared.
806 self.assertIn(exitcode,
807 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700808
Victor Stinner937ee9e2018-06-26 02:11:06 +0200809 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200810 def test_disable_windows_exc_handler(self):
811 code = dedent("""
812 import faulthandler
813 faulthandler.enable()
814 faulthandler.disable()
815 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
816 faulthandler._raise_exception(code)
817 """)
818 output, exitcode = self.get_output(code)
819 self.assertEqual(output, [])
820 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100821
Thomas A Caswelle2783352019-08-29 12:30:04 -0400822 def test_cancel_later_without_dump_traceback_later(self):
823 # bpo-37933: Calling cancel_dump_traceback_later()
824 # without dump_traceback_later() must not segfault.
825 code = dedent("""
826 import faulthandler
827 faulthandler.cancel_dump_traceback_later()
828 """)
829 output, exitcode = self.get_output(code)
830 self.assertEqual(output, [])
831 self.assertEqual(exitcode, 0)
832
Victor Stinner024e37a2011-03-31 01:31:06 +0200833
Victor Stinner024e37a2011-03-31 01:31:06 +0200834if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400835 unittest.main()