blob: f0be91844ffa7cba4fb4ab92c55e69b26a076ff2 [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
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020012import threading
Victor Stinner024e37a2011-03-31 01:31:06 +020013import unittest
Victor Stinner6d201682014-08-10 19:50:08 +020014from textwrap import dedent
Victor Stinner024e37a2011-03-31 01:31:06 +020015
Victor Stinnerff4cd882011-04-07 11:50:25 +020016try:
Victor Stinner56e8c292014-07-21 12:30:22 +020017 import _testcapi
18except ImportError:
19 _testcapi = None
Victor Stinnerff4cd882011-04-07 11:50:25 +020020
Victor Stinner44378d42011-04-01 15:37:12 +020021TIMEOUT = 0.5
Victor Stinner937ee9e2018-06-26 02:11:06 +020022MS_WINDOWS = (os.name == 'nt')
Gregory P. Smith30e02322018-12-30 18:09:26 -080023_cflags = sysconfig.get_config_var('CFLAGS') or ''
24_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
25UB_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080026 '-fsanitize=undefined' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080027 '--with-undefined-behavior-sanitizer' in _config_args
Gregory P. Smithb474e672018-12-30 17:05:36 -080028)
Gregory P. Smith30e02322018-12-30 18:09:26 -080029MEMORY_SANITIZER = (
Gregory P. Smithd6f45b22018-12-30 20:15:41 -080030 '-fsanitize=memory' in _cflags or
Gregory P. Smith30e02322018-12-30 18:09:26 -080031 '--with-memory-sanitizer' in _config_args
32)
33
Victor Stinner44378d42011-04-01 15:37:12 +020034
Victor Stinner301f3f02011-06-01 13:49:12 +020035def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020036 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020037 regex += ' File "<string>", line %s in func\n' % lineno1
38 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020039 if 1 < min_count:
40 return '^' + (regex + '\n') * (min_count - 1) + regex
41 else:
42 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020043
xdegayeef838062017-11-29 11:43:23 +010044def skip_segfault_on_android(test):
45 # Issue #32138: Raising SIGSEGV on Android may not cause a crash.
Victor Stinner937ee9e2018-06-26 02:11:06 +020046 return unittest.skipIf(is_android,
xdegayeef838062017-11-29 11:43:23 +010047 'raising SIGSEGV on Android is unreliable')(test)
48
Victor Stinner024e37a2011-03-31 01:31:06 +020049@contextmanager
50def temporary_filename():
51 filename = tempfile.mktemp()
52 try:
53 yield filename
54 finally:
55 support.unlink(filename)
56
57class FaultHandlerTests(unittest.TestCase):
Victor Stinner95bb7142015-03-12 15:32:03 +010058 def get_output(self, code, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020059 """
60 Run the specified code in Python (in a new child process) and read the
61 output from the standard error or from a file (if filename is set).
62 Return the output lines as a list.
63
64 Strip the reference count from the standard error for Python debug
65 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
66 thread XXX".
67 """
Victor Stinner6d201682014-08-10 19:50:08 +020068 code = dedent(code).strip()
Victor Stinner95bb7142015-03-12 15:32:03 +010069 pass_fds = []
70 if fd is not None:
71 pass_fds.append(fd)
Antoine Pitrou77e904e2013-10-08 23:04:32 +020072 with support.SuppressCrashReport():
Victor Stinner95bb7142015-03-12 15:32:03 +010073 process = script_helper.spawn_python('-c', code, pass_fds=pass_fds)
Victor Stinner861d9ab2016-03-16 22:45:24 +010074 with process:
75 stdout, stderr = process.communicate()
76 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020077 output = support.strip_python_stderr(stdout)
78 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020079 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020080 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020081 with open(filename, "rb") as fp:
82 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020083 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010084 elif fd is not None:
85 self.assertEqual(output, '')
86 os.lseek(fd, os.SEEK_SET, 0)
87 with open(fd, "rb", closefd=False) as fp:
88 output = fp.read()
89 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020090 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020091
Victor Stinner404cdc52016-03-23 10:39:17 +010092 def check_error(self, code, line_number, fatal_error, *,
93 filename=None, all_threads=True, other_regex=None,
94 fd=None, know_current_thread=True):
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 """
114 regex = dedent(regex.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200115 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100116 fatal_error=fatal_error,
Victor Stinner861d9ab2016-03-16 22:45:24 +0100117 header=header)).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200118 if other_regex:
119 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100120 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200121 output = '\n'.join(output)
122 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200123 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200124
Victor Stinner404cdc52016-03-23 10:39:17 +0100125 def check_fatal_error(self, code, line_number, name_regex, **kw):
126 fatal_error = 'Fatal Python error: %s' % name_regex
127 self.check_error(code, line_number, fatal_error, **kw)
128
129 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100130 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100131 self.check_error(code, line_number, fatal_error, **kw)
132
Victor Stinner330426c2013-07-03 22:29:42 +0200133 @unittest.skipIf(sys.platform.startswith('aix'),
134 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200135 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200136 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100137 self.check_fatal_error("""
138 import faulthandler
139 faulthandler.enable()
140 faulthandler._read_null()
141 """,
142 3,
143 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
144 '(?:Segmentation fault'
145 '|Bus error'
146 '|Illegal instruction)')
147 else:
148 self.check_windows_exception("""
149 import faulthandler
150 faulthandler.enable()
151 faulthandler._read_null()
152 """,
153 3,
154 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200155
xdegayeef838062017-11-29 11:43:23 +0100156 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200157 def test_sigsegv(self):
158 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200159 import faulthandler
160 faulthandler.enable()
161 faulthandler._sigsegv()
162 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200163 3,
164 'Segmentation fault')
165
Victor Stinner861d9ab2016-03-16 22:45:24 +0100166 def test_fatal_error_c_thread(self):
167 self.check_fatal_error("""
168 import faulthandler
169 faulthandler.enable()
170 faulthandler._fatal_error_c_thread()
171 """,
172 3,
173 'in new thread',
174 know_current_thread=False)
175
Victor Stinnerd727e232011-04-01 12:13:55 +0200176 def test_sigabrt(self):
177 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200178 import faulthandler
179 faulthandler.enable()
180 faulthandler._sigabrt()
181 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200182 3,
183 'Aborted')
184
Victor Stinner024e37a2011-03-31 01:31:06 +0200185 @unittest.skipIf(sys.platform == 'win32',
186 "SIGFPE cannot be caught on Windows")
187 def test_sigfpe(self):
188 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200189 import faulthandler
190 faulthandler.enable()
191 faulthandler._sigfpe()
192 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200193 3,
194 'Floating point exception')
195
Victor Stinner56e8c292014-07-21 12:30:22 +0200196 @unittest.skipIf(_testcapi is None, 'need _testcapi')
197 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100198 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200199 def test_sigbus(self):
200 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200201 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200202 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200203
Victor Stinner6d201682014-08-10 19:50:08 +0200204 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800205 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200206 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800207 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200208 'Bus error')
209
Victor Stinner56e8c292014-07-21 12:30:22 +0200210 @unittest.skipIf(_testcapi is None, 'need _testcapi')
211 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100212 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200213 def test_sigill(self):
214 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200215 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200216 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200217
Victor Stinner6d201682014-08-10 19:50:08 +0200218 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800219 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200220 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800221 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200222 'Illegal instruction')
223
224 def test_fatal_error(self):
225 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200226 import faulthandler
227 faulthandler._fatal_error(b'xyz')
228 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200229 2,
230 'xyz')
231
Victor Stinner57003f82016-03-15 17:23:35 +0100232 def test_fatal_error_without_gil(self):
233 self.check_fatal_error("""
234 import faulthandler
235 faulthandler._fatal_error(b'xyz', True)
236 """,
237 2,
238 'xyz')
239
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200240 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200241 "Issue #12868: sigaltstack() doesn't work on "
242 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200243 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
244 'need faulthandler._stack_overflow()')
245 def test_stack_overflow(self):
246 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200247 import faulthandler
248 faulthandler.enable()
249 faulthandler._stack_overflow()
250 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200251 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200252 '(?:Segmentation fault|Bus error)',
253 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200254
xdegayeef838062017-11-29 11:43:23 +0100255 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200256 def test_gil_released(self):
257 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200258 import faulthandler
259 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200260 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200261 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200262 3,
Victor Stinner50838282014-09-30 13:54:14 +0200263 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200264
Gregory P. Smith30e02322018-12-30 18:09:26 -0800265 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800266 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100267 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200268 def test_enable_file(self):
269 with temporary_filename() as filename:
270 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200271 import faulthandler
272 output = open({filename}, 'wb')
273 faulthandler.enable(output)
274 faulthandler._sigsegv()
275 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200276 4,
Victor Stinner56785392013-06-17 23:37:59 +0200277 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200278 filename=filename)
279
Victor Stinnerff2a6612015-03-13 11:01:30 +0100280 @unittest.skipIf(sys.platform == "win32",
281 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800282 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800283 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100284 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100285 def test_enable_fd(self):
286 with tempfile.TemporaryFile('wb+') as fp:
287 fd = fp.fileno()
288 self.check_fatal_error("""
289 import faulthandler
290 import sys
291 faulthandler.enable(%s)
292 faulthandler._sigsegv()
293 """ % fd,
294 4,
295 'Segmentation fault',
296 fd=fd)
297
xdegayeef838062017-11-29 11:43:23 +0100298 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200299 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200300 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200301 import faulthandler
302 faulthandler.enable(all_threads=False)
303 faulthandler._sigsegv()
304 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200305 3,
Victor Stinner56785392013-06-17 23:37:59 +0200306 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200307 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200308
xdegayeef838062017-11-29 11:43:23 +0100309 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200310 def test_disable(self):
311 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200312 import faulthandler
313 faulthandler.enable()
314 faulthandler.disable()
315 faulthandler._sigsegv()
316 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200317 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200318 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200319 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200320 self.assertTrue(not_expected not in stderr,
321 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200322 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200323
324 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200325 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200326 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200327 # regrtest may replace sys.stderr by io.StringIO object, but
328 # faulthandler.enable() requires that sys.stderr has a fileno()
329 # method
Victor Stinner72488502011-06-29 23:24:31 +0200330 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200331
332 was_enabled = faulthandler.is_enabled()
333 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200334 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200335 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200336 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200337 self.assertFalse(faulthandler.is_enabled())
338 finally:
339 if was_enabled:
340 faulthandler.enable()
341 else:
342 faulthandler.disable()
343 finally:
344 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200345
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200346 def test_disabled_by_default(self):
347 # By default, the module should be disabled
348 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100349 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800350 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100351 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200352 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200353
354 def test_sys_xoptions(self):
355 # Test python -X faulthandler
356 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800357 args = filter(None, (sys.executable,
358 "-E" if sys.flags.ignore_environment else "",
359 "-X", "faulthandler", "-c", code))
360 env = os.environ.copy()
361 env.pop("PYTHONFAULTHANDLER", None)
362 # don't use assert_python_ok() because it always enables faulthandler
363 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200364 self.assertEqual(output.rstrip(), b"True")
365
366 def test_env_var(self):
367 # empty env var
368 code = "import faulthandler; print(faulthandler.is_enabled())"
369 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100370 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200371 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100372 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800373 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200374 output = subprocess.check_output(args, env=env)
375 self.assertEqual(output.rstrip(), b"False")
376
377 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100378 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200379 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100380 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200381 output = subprocess.check_output(args, env=env)
382 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200383
Victor Stinner95bb7142015-03-12 15:32:03 +0100384 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200385 """
386 Explicitly call dump_traceback() function and check its output.
387 Raise an error if the output doesn't match the expected format.
388 """
389 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200390 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200391
Victor Stinner95bb7142015-03-12 15:32:03 +0100392 filename = {filename!r}
393 fd = {fd}
394
Victor Stinner6d201682014-08-10 19:50:08 +0200395 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100396 if filename:
397 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200398 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100399 elif fd is not None:
400 faulthandler.dump_traceback(fd,
401 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200402 else:
403 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200404
Victor Stinner6d201682014-08-10 19:50:08 +0200405 def funcA():
406 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200407
Victor Stinner6d201682014-08-10 19:50:08 +0200408 funcA()
409 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200410 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100411 filename=filename,
412 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200413 )
414 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100415 lineno = 9
416 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300417 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200418 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100419 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200420 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700421 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200422 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100423 ' File "<string>", line 17 in funcA',
424 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200425 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100426 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200427 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200428 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200429
430 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100431 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200432
433 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200434 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100435 self.check_dump_traceback(filename=filename)
436
Victor Stinnerff2a6612015-03-13 11:01:30 +0100437 @unittest.skipIf(sys.platform == "win32",
438 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100439 def test_dump_traceback_fd(self):
440 with tempfile.TemporaryFile('wb+') as fp:
441 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200442
Victor Stinner53386d82012-08-01 19:45:34 +0200443 def test_truncate(self):
444 maxlen = 500
445 func_name = 'x' * (maxlen + 50)
446 truncated = 'x' * maxlen + '...'
447 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200448 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200449
Victor Stinner6d201682014-08-10 19:50:08 +0200450 def {func_name}():
451 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200452
Victor Stinner6d201682014-08-10 19:50:08 +0200453 {func_name}()
454 """
Victor Stinner53386d82012-08-01 19:45:34 +0200455 code = code.format(
456 func_name=func_name,
457 )
458 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700459 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200460 ' File "<string>", line 4 in %s' % truncated,
461 ' File "<string>", line 6 in <module>'
462 ]
463 trace, exitcode = self.get_output(code)
464 self.assertEqual(trace, expected)
465 self.assertEqual(exitcode, 0)
466
Victor Stinner024e37a2011-03-31 01:31:06 +0200467 def check_dump_traceback_threads(self, filename):
468 """
469 Call explicitly dump_traceback(all_threads=True) and check the output.
470 Raise an error if the output doesn't match the expected format.
471 """
472 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200473 import faulthandler
474 from threading import Thread, Event
475 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200476
Victor Stinner6d201682014-08-10 19:50:08 +0200477 def dump():
478 if {filename}:
479 with open({filename}, "wb") as fp:
480 faulthandler.dump_traceback(fp, all_threads=True)
481 else:
482 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200483
Victor Stinner6d201682014-08-10 19:50:08 +0200484 class Waiter(Thread):
485 # avoid blocking if the main thread raises an exception.
486 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200487
Victor Stinner6d201682014-08-10 19:50:08 +0200488 def __init__(self):
489 Thread.__init__(self)
490 self.running = Event()
491 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200492
Victor Stinner6d201682014-08-10 19:50:08 +0200493 def run(self):
494 self.running.set()
495 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200496
Victor Stinner6d201682014-08-10 19:50:08 +0200497 waiter = Waiter()
498 waiter.start()
499 waiter.running.wait()
500 dump()
501 waiter.stop.set()
502 waiter.join()
503 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200504 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200505 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200506 output = '\n'.join(output)
507 if filename:
508 lineno = 8
509 else:
510 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400511 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200512 ^Thread 0x[0-9a-f]+ \(most recent call first\):
513 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
514 ){{1,3}} File "<string>", line 23 in run
515 File ".*threading.py", line [0-9]+ in _bootstrap_inner
516 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200517
Victor Stinner861d9ab2016-03-16 22:45:24 +0100518 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200519 File "<string>", line {lineno} in dump
520 File "<string>", line 28 in <module>$
521 """
522 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200523 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200524 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200525
526 def test_dump_traceback_threads(self):
527 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200528
529 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200530 with temporary_filename() as filename:
531 self.check_dump_traceback_threads(filename)
532
Victor Stinner95bb7142015-03-12 15:32:03 +0100533 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
534 'need faulthandler.dump_traceback_later()')
535 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
536 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200537 """
538 Check how many times the traceback is written in timeout x 2.5 seconds,
539 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
540 on repeat and cancel options.
541
542 Raise an error if the output doesn't match the expect format.
543 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200544 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200545 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200546 import faulthandler
547 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100548 import sys
549
550 timeout = {timeout}
551 repeat = {repeat}
552 cancel = {cancel}
553 loops = {loops}
554 filename = {filename!r}
555 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200556
Victor Stinner6d201682014-08-10 19:50:08 +0200557 def func(timeout, repeat, cancel, file, loops):
558 for loop in range(loops):
559 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
560 if cancel:
561 faulthandler.cancel_dump_traceback_later()
562 time.sleep(timeout * 5)
563 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200564
Victor Stinner95bb7142015-03-12 15:32:03 +0100565 if filename:
566 file = open(filename, "wb")
567 elif fd is not None:
568 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200569 else:
570 file = None
571 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100572 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200573 file.close()
574 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200575 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200576 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200577 repeat=repeat,
578 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200579 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100580 filename=filename,
581 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200582 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200583 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200584 trace = '\n'.join(trace)
585
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200586 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200587 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200588 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200589 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700590 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100591 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200592 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200593 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200594 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200595 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200596
Georg Brandldeb92b52012-09-22 08:58:55 +0200597 def test_dump_traceback_later(self):
598 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200599
Georg Brandldeb92b52012-09-22 08:58:55 +0200600 def test_dump_traceback_later_repeat(self):
601 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200602
Georg Brandldeb92b52012-09-22 08:58:55 +0200603 def test_dump_traceback_later_cancel(self):
604 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200605
Georg Brandldeb92b52012-09-22 08:58:55 +0200606 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100607 with temporary_filename() as filename:
608 self.check_dump_traceback_later(filename=filename)
609
Victor Stinnerff2a6612015-03-13 11:01:30 +0100610 @unittest.skipIf(sys.platform == "win32",
611 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100612 def test_dump_traceback_later_fd(self):
613 with tempfile.TemporaryFile('wb+') as fp:
614 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200615
Georg Brandldeb92b52012-09-22 08:58:55 +0200616 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100617 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200618
Victor Stinner024e37a2011-03-31 01:31:06 +0200619 @unittest.skipIf(not hasattr(faulthandler, "register"),
620 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200621 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100622 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200623 """
624 Register a handler displaying the traceback on a user signal. Raise the
625 signal and check the written traceback.
626
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200627 If chain is True, check that the previous signal handler is called.
628
Victor Stinner024e37a2011-03-31 01:31:06 +0200629 Raise an error if the output doesn't match the expected format.
630 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200631 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200632 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200633 import faulthandler
634 import os
635 import signal
636 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200637
Victor Stinner95bb7142015-03-12 15:32:03 +0100638 all_threads = {all_threads}
639 signum = {signum}
640 unregister = {unregister}
641 chain = {chain}
642 filename = {filename!r}
643 fd = {fd}
644
Victor Stinner6d201682014-08-10 19:50:08 +0200645 def func(signum):
646 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200647
Victor Stinner6d201682014-08-10 19:50:08 +0200648 def handler(signum, frame):
649 handler.called = True
650 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200651
Victor Stinner95bb7142015-03-12 15:32:03 +0100652 if filename:
653 file = open(filename, "wb")
654 elif fd is not None:
655 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200656 else:
657 file = None
658 if chain:
659 signal.signal(signum, handler)
660 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100661 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200662 if unregister:
663 faulthandler.unregister(signum)
664 func(signum)
665 if chain and not handler.called:
666 if file is not None:
667 output = file
668 else:
669 output = sys.stderr
670 print("Error: signal handler not called!", file=output)
671 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100672 else:
673 exitcode = 0
674 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200675 file.close()
676 sys.exit(exitcode)
677 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200678 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200679 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200680 signum=signum,
681 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200682 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100683 filename=filename,
684 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200685 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200686 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200687 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200688 if not unregister:
689 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400690 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200691 else:
R David Murray44b548d2016-09-08 13:59:53 -0400692 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100693 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200694 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200695 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200696 self.assertEqual(trace, '')
697 if unregister:
698 self.assertNotEqual(exitcode, 0)
699 else:
700 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200701
702 def test_register(self):
703 self.check_register()
704
Victor Stinnera01ca122011-04-01 12:56:17 +0200705 def test_unregister(self):
706 self.check_register(unregister=True)
707
Victor Stinner024e37a2011-03-31 01:31:06 +0200708 def test_register_file(self):
709 with temporary_filename() as filename:
710 self.check_register(filename=filename)
711
Victor Stinnerff2a6612015-03-13 11:01:30 +0100712 @unittest.skipIf(sys.platform == "win32",
713 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100714 def test_register_fd(self):
715 with tempfile.TemporaryFile('wb+') as fp:
716 self.check_register(fd=fp.fileno())
717
Victor Stinner024e37a2011-03-31 01:31:06 +0200718 def test_register_threads(self):
719 self.check_register(all_threads=True)
720
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200721 def test_register_chain(self):
722 self.check_register(chain=True)
723
Victor Stinnere2d66902014-05-14 17:15:50 +0200724 @contextmanager
725 def check_stderr_none(self):
726 stderr = sys.stderr
727 try:
728 sys.stderr = None
729 with self.assertRaises(RuntimeError) as cm:
730 yield
731 self.assertEqual(str(cm.exception), "sys.stderr is None")
732 finally:
733 sys.stderr = stderr
734
735 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300736 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200737 # instead of just an attribute error: "None has no attribute fileno".
738 with self.check_stderr_none():
739 faulthandler.enable()
740 with self.check_stderr_none():
741 faulthandler.dump_traceback()
742 if hasattr(faulthandler, 'dump_traceback_later'):
743 with self.check_stderr_none():
744 faulthandler.dump_traceback_later(1e-3)
745 if hasattr(faulthandler, "register"):
746 with self.check_stderr_none():
747 faulthandler.register(signal.SIGUSR1)
748
Victor Stinner937ee9e2018-06-26 02:11:06 +0200749 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100750 def test_raise_exception(self):
751 for exc, name in (
752 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
753 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
754 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
755 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400756 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100757 import faulthandler
758 faulthandler.enable()
759 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400760 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100761 3,
762 name)
763
Victor Stinner937ee9e2018-06-26 02:11:06 +0200764 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700765 def test_ignore_exception(self):
766 for exc_code in (
767 0xE06D7363, # MSC exception ("Emsc")
768 0xE0434352, # COM Callable Runtime exception ("ECCR")
769 ):
770 code = f"""
771 import faulthandler
772 faulthandler.enable()
773 faulthandler._raise_exception({exc_code})
774 """
775 code = dedent(code)
776 output, exitcode = self.get_output(code)
777 self.assertEqual(output, [])
778 self.assertEqual(exitcode, exc_code)
779
Victor Stinner937ee9e2018-06-26 02:11:06 +0200780 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700781 def test_raise_nonfatal_exception(self):
782 # These exceptions are not strictly errors. Letting
783 # faulthandler display the traceback when they are
784 # raised is likely to result in noise. However, they
785 # may still terminate the process if there is no
786 # handler installed for them (which there typically
787 # is, e.g. for debug messages).
788 for exc in (
789 0x00000000,
790 0x34567890,
791 0x40000000,
792 0x40001000,
793 0x70000000,
794 0x7FFFFFFF,
795 ):
796 output, exitcode = self.get_output(f"""
797 import faulthandler
798 faulthandler.enable()
799 faulthandler._raise_exception(0x{exc:x})
800 """
801 )
802 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200803 # On Windows older than 7 SP1, the actual exception code has
804 # bit 29 cleared.
805 self.assertIn(exitcode,
806 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700807
Victor Stinner937ee9e2018-06-26 02:11:06 +0200808 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200809 def test_disable_windows_exc_handler(self):
810 code = dedent("""
811 import faulthandler
812 faulthandler.enable()
813 faulthandler.disable()
814 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
815 faulthandler._raise_exception(code)
816 """)
817 output, exitcode = self.get_output(code)
818 self.assertEqual(output, [])
819 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100820
Victor Stinner024e37a2011-03-31 01:31:06 +0200821
Victor Stinner024e37a2011-03-31 01:31:06 +0200822if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400823 unittest.main()