blob: a4427a537d1f865746ba4cbf58e2b8f06380e8d5 [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 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
539 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200540 """
541 Check how many times the traceback is written in timeout x 2.5 seconds,
542 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
543 on repeat and cancel options.
544
545 Raise an error if the output doesn't match the expect format.
546 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200547 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200548 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200549 import faulthandler
550 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100551 import sys
552
553 timeout = {timeout}
554 repeat = {repeat}
555 cancel = {cancel}
556 loops = {loops}
557 filename = {filename!r}
558 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200559
Victor Stinner6d201682014-08-10 19:50:08 +0200560 def func(timeout, repeat, cancel, file, loops):
561 for loop in range(loops):
562 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
563 if cancel:
564 faulthandler.cancel_dump_traceback_later()
565 time.sleep(timeout * 5)
566 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200567
Victor Stinner95bb7142015-03-12 15:32:03 +0100568 if filename:
569 file = open(filename, "wb")
570 elif fd is not None:
571 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200572 else:
573 file = None
574 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100575 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200576 file.close()
577 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200578 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200579 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200580 repeat=repeat,
581 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200582 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100583 filename=filename,
584 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200585 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200586 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200587 trace = '\n'.join(trace)
588
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200589 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200590 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200591 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200592 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700593 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100594 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200595 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200596 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200597 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200598 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200599
Georg Brandldeb92b52012-09-22 08:58:55 +0200600 def test_dump_traceback_later(self):
601 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200602
Georg Brandldeb92b52012-09-22 08:58:55 +0200603 def test_dump_traceback_later_repeat(self):
604 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200605
Georg Brandldeb92b52012-09-22 08:58:55 +0200606 def test_dump_traceback_later_cancel(self):
607 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200608
Georg Brandldeb92b52012-09-22 08:58:55 +0200609 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100610 with temporary_filename() as filename:
611 self.check_dump_traceback_later(filename=filename)
612
Victor Stinnerff2a6612015-03-13 11:01:30 +0100613 @unittest.skipIf(sys.platform == "win32",
614 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100615 def test_dump_traceback_later_fd(self):
616 with tempfile.TemporaryFile('wb+') as fp:
617 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200618
Georg Brandldeb92b52012-09-22 08:58:55 +0200619 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100620 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200621
Victor Stinner024e37a2011-03-31 01:31:06 +0200622 @unittest.skipIf(not hasattr(faulthandler, "register"),
623 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200624 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100625 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200626 """
627 Register a handler displaying the traceback on a user signal. Raise the
628 signal and check the written traceback.
629
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200630 If chain is True, check that the previous signal handler is called.
631
Victor Stinner024e37a2011-03-31 01:31:06 +0200632 Raise an error if the output doesn't match the expected format.
633 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200634 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200635 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200636 import faulthandler
637 import os
638 import signal
639 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200640
Victor Stinner95bb7142015-03-12 15:32:03 +0100641 all_threads = {all_threads}
642 signum = {signum}
643 unregister = {unregister}
644 chain = {chain}
645 filename = {filename!r}
646 fd = {fd}
647
Victor Stinner6d201682014-08-10 19:50:08 +0200648 def func(signum):
649 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200650
Victor Stinner6d201682014-08-10 19:50:08 +0200651 def handler(signum, frame):
652 handler.called = True
653 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200654
Victor Stinner95bb7142015-03-12 15:32:03 +0100655 if filename:
656 file = open(filename, "wb")
657 elif fd is not None:
658 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200659 else:
660 file = None
661 if chain:
662 signal.signal(signum, handler)
663 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100664 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200665 if unregister:
666 faulthandler.unregister(signum)
667 func(signum)
668 if chain and not handler.called:
669 if file is not None:
670 output = file
671 else:
672 output = sys.stderr
673 print("Error: signal handler not called!", file=output)
674 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100675 else:
676 exitcode = 0
677 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200678 file.close()
679 sys.exit(exitcode)
680 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200681 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200682 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200683 signum=signum,
684 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200685 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100686 filename=filename,
687 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200688 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200689 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200690 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200691 if not unregister:
692 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400693 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200694 else:
R David Murray44b548d2016-09-08 13:59:53 -0400695 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100696 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200697 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200698 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200699 self.assertEqual(trace, '')
700 if unregister:
701 self.assertNotEqual(exitcode, 0)
702 else:
703 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200704
705 def test_register(self):
706 self.check_register()
707
Victor Stinnera01ca122011-04-01 12:56:17 +0200708 def test_unregister(self):
709 self.check_register(unregister=True)
710
Victor Stinner024e37a2011-03-31 01:31:06 +0200711 def test_register_file(self):
712 with temporary_filename() as filename:
713 self.check_register(filename=filename)
714
Victor Stinnerff2a6612015-03-13 11:01:30 +0100715 @unittest.skipIf(sys.platform == "win32",
716 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100717 def test_register_fd(self):
718 with tempfile.TemporaryFile('wb+') as fp:
719 self.check_register(fd=fp.fileno())
720
Victor Stinner024e37a2011-03-31 01:31:06 +0200721 def test_register_threads(self):
722 self.check_register(all_threads=True)
723
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200724 def test_register_chain(self):
725 self.check_register(chain=True)
726
Victor Stinnere2d66902014-05-14 17:15:50 +0200727 @contextmanager
728 def check_stderr_none(self):
729 stderr = sys.stderr
730 try:
731 sys.stderr = None
732 with self.assertRaises(RuntimeError) as cm:
733 yield
734 self.assertEqual(str(cm.exception), "sys.stderr is None")
735 finally:
736 sys.stderr = stderr
737
738 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300739 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200740 # instead of just an attribute error: "None has no attribute fileno".
741 with self.check_stderr_none():
742 faulthandler.enable()
743 with self.check_stderr_none():
744 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200745 with self.check_stderr_none():
746 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200747 if hasattr(faulthandler, "register"):
748 with self.check_stderr_none():
749 faulthandler.register(signal.SIGUSR1)
750
Victor Stinner937ee9e2018-06-26 02:11:06 +0200751 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100752 def test_raise_exception(self):
753 for exc, name in (
754 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
755 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
756 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
757 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400758 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100759 import faulthandler
760 faulthandler.enable()
761 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400762 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100763 3,
764 name)
765
Victor Stinner937ee9e2018-06-26 02:11:06 +0200766 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700767 def test_ignore_exception(self):
768 for exc_code in (
769 0xE06D7363, # MSC exception ("Emsc")
770 0xE0434352, # COM Callable Runtime exception ("ECCR")
771 ):
772 code = f"""
773 import faulthandler
774 faulthandler.enable()
775 faulthandler._raise_exception({exc_code})
776 """
777 code = dedent(code)
778 output, exitcode = self.get_output(code)
779 self.assertEqual(output, [])
780 self.assertEqual(exitcode, exc_code)
781
Victor Stinner937ee9e2018-06-26 02:11:06 +0200782 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700783 def test_raise_nonfatal_exception(self):
784 # These exceptions are not strictly errors. Letting
785 # faulthandler display the traceback when they are
786 # raised is likely to result in noise. However, they
787 # may still terminate the process if there is no
788 # handler installed for them (which there typically
789 # is, e.g. for debug messages).
790 for exc in (
791 0x00000000,
792 0x34567890,
793 0x40000000,
794 0x40001000,
795 0x70000000,
796 0x7FFFFFFF,
797 ):
798 output, exitcode = self.get_output(f"""
799 import faulthandler
800 faulthandler.enable()
801 faulthandler._raise_exception(0x{exc:x})
802 """
803 )
804 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200805 # On Windows older than 7 SP1, the actual exception code has
806 # bit 29 cleared.
807 self.assertIn(exitcode,
808 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700809
Victor Stinner937ee9e2018-06-26 02:11:06 +0200810 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200811 def test_disable_windows_exc_handler(self):
812 code = dedent("""
813 import faulthandler
814 faulthandler.enable()
815 faulthandler.disable()
816 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
817 faulthandler._raise_exception(code)
818 """)
819 output, exitcode = self.get_output(code)
820 self.assertEqual(output, [])
821 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100822
Thomas A Caswelle2783352019-08-29 12:30:04 -0400823 def test_cancel_later_without_dump_traceback_later(self):
824 # bpo-37933: Calling cancel_dump_traceback_later()
825 # without dump_traceback_later() must not segfault.
826 code = dedent("""
827 import faulthandler
828 faulthandler.cancel_dump_traceback_later()
829 """)
830 output, exitcode = self.get_output(code)
831 self.assertEqual(output, [])
832 self.assertEqual(exitcode, 0)
833
Victor Stinner024e37a2011-03-31 01:31:06 +0200834
Victor Stinner024e37a2011-03-31 01:31:06 +0200835if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400836 unittest.main()