blob: 6aee22be2e037013e962aa6dece21c8784fdc0ed [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 Stinner68e08082014-08-10 19:51:05 +0200201 import _testcapi
Victor Stinner6d201682014-08-10 19:50:08 +0200202 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200203 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200204
Victor Stinner6d201682014-08-10 19:50:08 +0200205 faulthandler.enable()
Victor Stinner68e08082014-08-10 19:51:05 +0200206 _testcapi.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200207 """,
Victor Stinner56e8c292014-07-21 12:30:22 +0200208 6,
Victor Stinner024e37a2011-03-31 01:31:06 +0200209 'Bus error')
210
Victor Stinner56e8c292014-07-21 12:30:22 +0200211 @unittest.skipIf(_testcapi is None, 'need _testcapi')
212 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100213 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200214 def test_sigill(self):
215 self.check_fatal_error("""
Victor Stinner68e08082014-08-10 19:51:05 +0200216 import _testcapi
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()
Victor Stinner68e08082014-08-10 19:51:05 +0200221 _testcapi.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200222 """,
Victor Stinner56e8c292014-07-21 12:30:22 +0200223 6,
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,
232 'xyz')
233
Victor Stinner57003f82016-03-15 17:23:35 +0100234 def test_fatal_error_without_gil(self):
235 self.check_fatal_error("""
236 import faulthandler
237 faulthandler._fatal_error(b'xyz', True)
238 """,
239 2,
240 'xyz')
241
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200242 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200243 "Issue #12868: sigaltstack() doesn't work on "
244 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200245 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
246 'need faulthandler._stack_overflow()')
247 def test_stack_overflow(self):
248 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200249 import faulthandler
250 faulthandler.enable()
251 faulthandler._stack_overflow()
252 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200253 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200254 '(?:Segmentation fault|Bus error)',
255 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200256
xdegayeef838062017-11-29 11:43:23 +0100257 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200258 def test_gil_released(self):
259 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200260 import faulthandler
261 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200262 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200263 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200264 3,
Victor Stinner50838282014-09-30 13:54:14 +0200265 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200266
Gregory P. Smith30e02322018-12-30 18:09:26 -0800267 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800268 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100269 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200270 def test_enable_file(self):
271 with temporary_filename() as filename:
272 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200273 import faulthandler
274 output = open({filename}, 'wb')
275 faulthandler.enable(output)
276 faulthandler._sigsegv()
277 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200278 4,
Victor Stinner56785392013-06-17 23:37:59 +0200279 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200280 filename=filename)
281
Victor Stinnerff2a6612015-03-13 11:01:30 +0100282 @unittest.skipIf(sys.platform == "win32",
283 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800284 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800285 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100286 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100287 def test_enable_fd(self):
288 with tempfile.TemporaryFile('wb+') as fp:
289 fd = fp.fileno()
290 self.check_fatal_error("""
291 import faulthandler
292 import sys
293 faulthandler.enable(%s)
294 faulthandler._sigsegv()
295 """ % fd,
296 4,
297 'Segmentation fault',
298 fd=fd)
299
xdegayeef838062017-11-29 11:43:23 +0100300 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200301 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200302 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200303 import faulthandler
304 faulthandler.enable(all_threads=False)
305 faulthandler._sigsegv()
306 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200307 3,
Victor Stinner56785392013-06-17 23:37:59 +0200308 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200309 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200310
xdegayeef838062017-11-29 11:43:23 +0100311 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200312 def test_disable(self):
313 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200314 import faulthandler
315 faulthandler.enable()
316 faulthandler.disable()
317 faulthandler._sigsegv()
318 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200319 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200320 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200321 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200322 self.assertTrue(not_expected not in stderr,
323 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200324 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200325
326 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200327 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200328 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200329 # regrtest may replace sys.stderr by io.StringIO object, but
330 # faulthandler.enable() requires that sys.stderr has a fileno()
331 # method
Victor Stinner72488502011-06-29 23:24:31 +0200332 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200333
334 was_enabled = faulthandler.is_enabled()
335 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200336 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200337 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200338 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200339 self.assertFalse(faulthandler.is_enabled())
340 finally:
341 if was_enabled:
342 faulthandler.enable()
343 else:
344 faulthandler.disable()
345 finally:
346 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200347
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200348 def test_disabled_by_default(self):
349 # By default, the module should be disabled
350 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100351 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800352 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100353 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200354 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200355
356 def test_sys_xoptions(self):
357 # Test python -X faulthandler
358 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800359 args = filter(None, (sys.executable,
360 "-E" if sys.flags.ignore_environment else "",
361 "-X", "faulthandler", "-c", code))
362 env = os.environ.copy()
363 env.pop("PYTHONFAULTHANDLER", None)
364 # don't use assert_python_ok() because it always enables faulthandler
365 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200366 self.assertEqual(output.rstrip(), b"True")
367
368 def test_env_var(self):
369 # empty env var
370 code = "import faulthandler; print(faulthandler.is_enabled())"
371 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100372 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200373 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100374 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800375 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200376 output = subprocess.check_output(args, env=env)
377 self.assertEqual(output.rstrip(), b"False")
378
379 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100380 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200381 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100382 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200383 output = subprocess.check_output(args, env=env)
384 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200385
Victor Stinner95bb7142015-03-12 15:32:03 +0100386 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200387 """
388 Explicitly call dump_traceback() function and check its output.
389 Raise an error if the output doesn't match the expected format.
390 """
391 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200392 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200393
Victor Stinner95bb7142015-03-12 15:32:03 +0100394 filename = {filename!r}
395 fd = {fd}
396
Victor Stinner6d201682014-08-10 19:50:08 +0200397 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100398 if filename:
399 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200400 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100401 elif fd is not None:
402 faulthandler.dump_traceback(fd,
403 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200404 else:
405 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200406
Victor Stinner6d201682014-08-10 19:50:08 +0200407 def funcA():
408 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200409
Victor Stinner6d201682014-08-10 19:50:08 +0200410 funcA()
411 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200412 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100413 filename=filename,
414 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200415 )
416 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100417 lineno = 9
418 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300419 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200420 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100421 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200422 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700423 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200424 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100425 ' File "<string>", line 17 in funcA',
426 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200427 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100428 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200429 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200430 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200431
432 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100433 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200434
435 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200436 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100437 self.check_dump_traceback(filename=filename)
438
Victor Stinnerff2a6612015-03-13 11:01:30 +0100439 @unittest.skipIf(sys.platform == "win32",
440 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100441 def test_dump_traceback_fd(self):
442 with tempfile.TemporaryFile('wb+') as fp:
443 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200444
Victor Stinner53386d82012-08-01 19:45:34 +0200445 def test_truncate(self):
446 maxlen = 500
447 func_name = 'x' * (maxlen + 50)
448 truncated = 'x' * maxlen + '...'
449 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200450 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200451
Victor Stinner6d201682014-08-10 19:50:08 +0200452 def {func_name}():
453 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200454
Victor Stinner6d201682014-08-10 19:50:08 +0200455 {func_name}()
456 """
Victor Stinner53386d82012-08-01 19:45:34 +0200457 code = code.format(
458 func_name=func_name,
459 )
460 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700461 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200462 ' File "<string>", line 4 in %s' % truncated,
463 ' File "<string>", line 6 in <module>'
464 ]
465 trace, exitcode = self.get_output(code)
466 self.assertEqual(trace, expected)
467 self.assertEqual(exitcode, 0)
468
Victor Stinner024e37a2011-03-31 01:31:06 +0200469 def check_dump_traceback_threads(self, filename):
470 """
471 Call explicitly dump_traceback(all_threads=True) and check the output.
472 Raise an error if the output doesn't match the expected format.
473 """
474 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200475 import faulthandler
476 from threading import Thread, Event
477 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200478
Victor Stinner6d201682014-08-10 19:50:08 +0200479 def dump():
480 if {filename}:
481 with open({filename}, "wb") as fp:
482 faulthandler.dump_traceback(fp, all_threads=True)
483 else:
484 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200485
Victor Stinner6d201682014-08-10 19:50:08 +0200486 class Waiter(Thread):
487 # avoid blocking if the main thread raises an exception.
488 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200489
Victor Stinner6d201682014-08-10 19:50:08 +0200490 def __init__(self):
491 Thread.__init__(self)
492 self.running = Event()
493 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200494
Victor Stinner6d201682014-08-10 19:50:08 +0200495 def run(self):
496 self.running.set()
497 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200498
Victor Stinner6d201682014-08-10 19:50:08 +0200499 waiter = Waiter()
500 waiter.start()
501 waiter.running.wait()
502 dump()
503 waiter.stop.set()
504 waiter.join()
505 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200506 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200507 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200508 output = '\n'.join(output)
509 if filename:
510 lineno = 8
511 else:
512 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400513 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200514 ^Thread 0x[0-9a-f]+ \(most recent call first\):
515 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
516 ){{1,3}} File "<string>", line 23 in run
517 File ".*threading.py", line [0-9]+ in _bootstrap_inner
518 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200519
Victor Stinner861d9ab2016-03-16 22:45:24 +0100520 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200521 File "<string>", line {lineno} in dump
522 File "<string>", line 28 in <module>$
523 """
524 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200525 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200526 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200527
528 def test_dump_traceback_threads(self):
529 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200530
531 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200532 with temporary_filename() as filename:
533 self.check_dump_traceback_threads(filename)
534
Victor Stinner95bb7142015-03-12 15:32:03 +0100535 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
536 'need faulthandler.dump_traceback_later()')
537 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()
744 if hasattr(faulthandler, 'dump_traceback_later'):
745 with self.check_stderr_none():
746 faulthandler.dump_traceback_later(1e-3)
747 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
Victor Stinner024e37a2011-03-31 01:31:06 +0200823
Victor Stinner024e37a2011-03-31 01:31:06 +0200824if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400825 unittest.main()