blob: b1aa8c32284ba3996c40e20d0c8990485540c352 [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,
93 fd=None, know_current_thread=True):
Victor Stinner024e37a2011-03-31 01:31:06 +020094 """
95 Check that the fault handler for fatal errors is enabled and check the
96 traceback from the child process output.
97
98 Raise an error if the output doesn't match the expected format.
99 """
100 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100101 if know_current_thread:
102 header = 'Current thread 0x[0-9a-f]+'
103 else:
104 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200105 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100106 header = 'Stack'
R David Murray44b548d2016-09-08 13:59:53 -0400107 regex = r"""
Gregory P. Smith30e02322018-12-30 18:09:26 -0800108 (?m)^{fatal_error}
Victor Stinner024e37a2011-03-31 01:31:06 +0200109
Victor Stinner861d9ab2016-03-16 22:45:24 +0100110 {header} \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200111 File "<string>", line {lineno} in <module>
112 """
113 regex = dedent(regex.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200114 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100115 fatal_error=fatal_error,
Victor Stinner861d9ab2016-03-16 22:45:24 +0100116 header=header)).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200117 if other_regex:
118 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100119 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200120 output = '\n'.join(output)
121 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200122 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200123
Victor Stinner404cdc52016-03-23 10:39:17 +0100124 def check_fatal_error(self, code, line_number, name_regex, **kw):
125 fatal_error = 'Fatal Python error: %s' % name_regex
126 self.check_error(code, line_number, fatal_error, **kw)
127
128 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100129 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100130 self.check_error(code, line_number, fatal_error, **kw)
131
Victor Stinner330426c2013-07-03 22:29:42 +0200132 @unittest.skipIf(sys.platform.startswith('aix'),
133 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200134 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200135 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100136 self.check_fatal_error("""
137 import faulthandler
138 faulthandler.enable()
139 faulthandler._read_null()
140 """,
141 3,
142 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
143 '(?:Segmentation fault'
144 '|Bus error'
145 '|Illegal instruction)')
146 else:
147 self.check_windows_exception("""
148 import faulthandler
149 faulthandler.enable()
150 faulthandler._read_null()
151 """,
152 3,
153 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200154
xdegayeef838062017-11-29 11:43:23 +0100155 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200156 def test_sigsegv(self):
157 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200158 import faulthandler
159 faulthandler.enable()
160 faulthandler._sigsegv()
161 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200162 3,
163 'Segmentation fault')
164
Victor Stinner861d9ab2016-03-16 22:45:24 +0100165 def test_fatal_error_c_thread(self):
166 self.check_fatal_error("""
167 import faulthandler
168 faulthandler.enable()
169 faulthandler._fatal_error_c_thread()
170 """,
171 3,
172 'in new thread',
173 know_current_thread=False)
174
Victor Stinnerd727e232011-04-01 12:13:55 +0200175 def test_sigabrt(self):
176 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200177 import faulthandler
178 faulthandler.enable()
179 faulthandler._sigabrt()
180 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200181 3,
182 'Aborted')
183
Victor Stinner024e37a2011-03-31 01:31:06 +0200184 @unittest.skipIf(sys.platform == 'win32',
185 "SIGFPE cannot be caught on Windows")
186 def test_sigfpe(self):
187 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200188 import faulthandler
189 faulthandler.enable()
190 faulthandler._sigfpe()
191 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200192 3,
193 'Floating point exception')
194
Victor Stinner56e8c292014-07-21 12:30:22 +0200195 @unittest.skipIf(_testcapi is None, 'need _testcapi')
196 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100197 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200198 def test_sigbus(self):
199 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200200 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200201 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200202
Victor Stinner6d201682014-08-10 19:50:08 +0200203 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800204 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200205 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800206 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200207 'Bus error')
208
Victor Stinner56e8c292014-07-21 12:30:22 +0200209 @unittest.skipIf(_testcapi is None, 'need _testcapi')
210 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100211 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200212 def test_sigill(self):
213 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200214 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200215 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200216
Victor Stinner6d201682014-08-10 19:50:08 +0200217 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800218 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200219 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800220 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200221 'Illegal instruction')
222
223 def test_fatal_error(self):
224 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200225 import faulthandler
226 faulthandler._fatal_error(b'xyz')
227 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200228 2,
229 'xyz')
230
Victor Stinner57003f82016-03-15 17:23:35 +0100231 def test_fatal_error_without_gil(self):
232 self.check_fatal_error("""
233 import faulthandler
234 faulthandler._fatal_error(b'xyz', True)
235 """,
236 2,
237 'xyz')
238
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200239 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200240 "Issue #12868: sigaltstack() doesn't work on "
241 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200242 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
243 'need faulthandler._stack_overflow()')
244 def test_stack_overflow(self):
245 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200246 import faulthandler
247 faulthandler.enable()
248 faulthandler._stack_overflow()
249 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200250 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200251 '(?:Segmentation fault|Bus error)',
252 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200253
xdegayeef838062017-11-29 11:43:23 +0100254 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200255 def test_gil_released(self):
256 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200257 import faulthandler
258 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200259 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200260 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200261 3,
Victor Stinner50838282014-09-30 13:54:14 +0200262 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200263
Gregory P. Smith30e02322018-12-30 18:09:26 -0800264 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800265 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100266 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200267 def test_enable_file(self):
268 with temporary_filename() as filename:
269 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200270 import faulthandler
271 output = open({filename}, 'wb')
272 faulthandler.enable(output)
273 faulthandler._sigsegv()
274 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200275 4,
Victor Stinner56785392013-06-17 23:37:59 +0200276 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200277 filename=filename)
278
Victor Stinnerff2a6612015-03-13 11:01:30 +0100279 @unittest.skipIf(sys.platform == "win32",
280 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800281 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800282 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100283 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100284 def test_enable_fd(self):
285 with tempfile.TemporaryFile('wb+') as fp:
286 fd = fp.fileno()
287 self.check_fatal_error("""
288 import faulthandler
289 import sys
290 faulthandler.enable(%s)
291 faulthandler._sigsegv()
292 """ % fd,
293 4,
294 'Segmentation fault',
295 fd=fd)
296
xdegayeef838062017-11-29 11:43:23 +0100297 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200298 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200299 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200300 import faulthandler
301 faulthandler.enable(all_threads=False)
302 faulthandler._sigsegv()
303 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200304 3,
Victor Stinner56785392013-06-17 23:37:59 +0200305 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200306 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200307
xdegayeef838062017-11-29 11:43:23 +0100308 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 def test_disable(self):
310 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200311 import faulthandler
312 faulthandler.enable()
313 faulthandler.disable()
314 faulthandler._sigsegv()
315 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200316 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200317 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200318 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200319 self.assertTrue(not_expected not in stderr,
320 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200321 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200322
323 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200324 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200325 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200326 # regrtest may replace sys.stderr by io.StringIO object, but
327 # faulthandler.enable() requires that sys.stderr has a fileno()
328 # method
Victor Stinner72488502011-06-29 23:24:31 +0200329 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200330
331 was_enabled = faulthandler.is_enabled()
332 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200333 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200334 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200335 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200336 self.assertFalse(faulthandler.is_enabled())
337 finally:
338 if was_enabled:
339 faulthandler.enable()
340 else:
341 faulthandler.disable()
342 finally:
343 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200344
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200345 def test_disabled_by_default(self):
346 # By default, the module should be disabled
347 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100348 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800349 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100350 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200351 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200352
353 def test_sys_xoptions(self):
354 # Test python -X faulthandler
355 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800356 args = filter(None, (sys.executable,
357 "-E" if sys.flags.ignore_environment else "",
358 "-X", "faulthandler", "-c", code))
359 env = os.environ.copy()
360 env.pop("PYTHONFAULTHANDLER", None)
361 # don't use assert_python_ok() because it always enables faulthandler
362 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200363 self.assertEqual(output.rstrip(), b"True")
364
365 def test_env_var(self):
366 # empty env var
367 code = "import faulthandler; print(faulthandler.is_enabled())"
368 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100369 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200370 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100371 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800372 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200373 output = subprocess.check_output(args, env=env)
374 self.assertEqual(output.rstrip(), b"False")
375
376 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100377 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200378 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100379 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200380 output = subprocess.check_output(args, env=env)
381 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200382
Victor Stinner95bb7142015-03-12 15:32:03 +0100383 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200384 """
385 Explicitly call dump_traceback() function and check its output.
386 Raise an error if the output doesn't match the expected format.
387 """
388 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200389 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200390
Victor Stinner95bb7142015-03-12 15:32:03 +0100391 filename = {filename!r}
392 fd = {fd}
393
Victor Stinner6d201682014-08-10 19:50:08 +0200394 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100395 if filename:
396 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200397 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100398 elif fd is not None:
399 faulthandler.dump_traceback(fd,
400 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200401 else:
402 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200403
Victor Stinner6d201682014-08-10 19:50:08 +0200404 def funcA():
405 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200406
Victor Stinner6d201682014-08-10 19:50:08 +0200407 funcA()
408 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200409 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100410 filename=filename,
411 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200412 )
413 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100414 lineno = 9
415 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300416 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200417 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100418 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200419 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700420 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200421 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100422 ' File "<string>", line 17 in funcA',
423 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200424 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100425 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200426 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200427 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200428
429 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100430 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200431
432 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200433 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100434 self.check_dump_traceback(filename=filename)
435
Victor Stinnerff2a6612015-03-13 11:01:30 +0100436 @unittest.skipIf(sys.platform == "win32",
437 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100438 def test_dump_traceback_fd(self):
439 with tempfile.TemporaryFile('wb+') as fp:
440 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200441
Victor Stinner53386d82012-08-01 19:45:34 +0200442 def test_truncate(self):
443 maxlen = 500
444 func_name = 'x' * (maxlen + 50)
445 truncated = 'x' * maxlen + '...'
446 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200447 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200448
Victor Stinner6d201682014-08-10 19:50:08 +0200449 def {func_name}():
450 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200451
Victor Stinner6d201682014-08-10 19:50:08 +0200452 {func_name}()
453 """
Victor Stinner53386d82012-08-01 19:45:34 +0200454 code = code.format(
455 func_name=func_name,
456 )
457 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700458 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200459 ' File "<string>", line 4 in %s' % truncated,
460 ' File "<string>", line 6 in <module>'
461 ]
462 trace, exitcode = self.get_output(code)
463 self.assertEqual(trace, expected)
464 self.assertEqual(exitcode, 0)
465
Victor Stinner024e37a2011-03-31 01:31:06 +0200466 def check_dump_traceback_threads(self, filename):
467 """
468 Call explicitly dump_traceback(all_threads=True) and check the output.
469 Raise an error if the output doesn't match the expected format.
470 """
471 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200472 import faulthandler
473 from threading import Thread, Event
474 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200475
Victor Stinner6d201682014-08-10 19:50:08 +0200476 def dump():
477 if {filename}:
478 with open({filename}, "wb") as fp:
479 faulthandler.dump_traceback(fp, all_threads=True)
480 else:
481 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200482
Victor Stinner6d201682014-08-10 19:50:08 +0200483 class Waiter(Thread):
484 # avoid blocking if the main thread raises an exception.
485 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200486
Victor Stinner6d201682014-08-10 19:50:08 +0200487 def __init__(self):
488 Thread.__init__(self)
489 self.running = Event()
490 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200491
Victor Stinner6d201682014-08-10 19:50:08 +0200492 def run(self):
493 self.running.set()
494 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200495
Victor Stinner6d201682014-08-10 19:50:08 +0200496 waiter = Waiter()
497 waiter.start()
498 waiter.running.wait()
499 dump()
500 waiter.stop.set()
501 waiter.join()
502 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200503 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200504 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200505 output = '\n'.join(output)
506 if filename:
507 lineno = 8
508 else:
509 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400510 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200511 ^Thread 0x[0-9a-f]+ \(most recent call first\):
512 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
513 ){{1,3}} File "<string>", line 23 in run
514 File ".*threading.py", line [0-9]+ in _bootstrap_inner
515 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200516
Victor Stinner861d9ab2016-03-16 22:45:24 +0100517 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200518 File "<string>", line {lineno} in dump
519 File "<string>", line 28 in <module>$
520 """
521 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200522 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200523 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200524
525 def test_dump_traceback_threads(self):
526 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200527
528 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200529 with temporary_filename() as filename:
530 self.check_dump_traceback_threads(filename)
531
Victor Stinner95bb7142015-03-12 15:32:03 +0100532 @unittest.skipIf(not hasattr(faulthandler, 'dump_traceback_later'),
533 'need faulthandler.dump_traceback_later()')
534 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
535 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200536 """
537 Check how many times the traceback is written in timeout x 2.5 seconds,
538 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
539 on repeat and cancel options.
540
541 Raise an error if the output doesn't match the expect format.
542 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200543 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200544 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200545 import faulthandler
546 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100547 import sys
548
549 timeout = {timeout}
550 repeat = {repeat}
551 cancel = {cancel}
552 loops = {loops}
553 filename = {filename!r}
554 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200555
Victor Stinner6d201682014-08-10 19:50:08 +0200556 def func(timeout, repeat, cancel, file, loops):
557 for loop in range(loops):
558 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
559 if cancel:
560 faulthandler.cancel_dump_traceback_later()
561 time.sleep(timeout * 5)
562 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200563
Victor Stinner95bb7142015-03-12 15:32:03 +0100564 if filename:
565 file = open(filename, "wb")
566 elif fd is not None:
567 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200568 else:
569 file = None
570 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100571 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200572 file.close()
573 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200574 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200575 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200576 repeat=repeat,
577 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200578 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100579 filename=filename,
580 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200581 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200582 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200583 trace = '\n'.join(trace)
584
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200585 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200586 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200587 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200588 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700589 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100590 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200591 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200592 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200593 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200594 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200595
Georg Brandldeb92b52012-09-22 08:58:55 +0200596 def test_dump_traceback_later(self):
597 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200598
Georg Brandldeb92b52012-09-22 08:58:55 +0200599 def test_dump_traceback_later_repeat(self):
600 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200601
Georg Brandldeb92b52012-09-22 08:58:55 +0200602 def test_dump_traceback_later_cancel(self):
603 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200604
Georg Brandldeb92b52012-09-22 08:58:55 +0200605 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100606 with temporary_filename() as filename:
607 self.check_dump_traceback_later(filename=filename)
608
Victor Stinnerff2a6612015-03-13 11:01:30 +0100609 @unittest.skipIf(sys.platform == "win32",
610 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100611 def test_dump_traceback_later_fd(self):
612 with tempfile.TemporaryFile('wb+') as fp:
613 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200614
Georg Brandldeb92b52012-09-22 08:58:55 +0200615 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100616 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200617
Victor Stinner024e37a2011-03-31 01:31:06 +0200618 @unittest.skipIf(not hasattr(faulthandler, "register"),
619 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200620 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100621 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200622 """
623 Register a handler displaying the traceback on a user signal. Raise the
624 signal and check the written traceback.
625
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200626 If chain is True, check that the previous signal handler is called.
627
Victor Stinner024e37a2011-03-31 01:31:06 +0200628 Raise an error if the output doesn't match the expected format.
629 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200630 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200631 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200632 import faulthandler
633 import os
634 import signal
635 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200636
Victor Stinner95bb7142015-03-12 15:32:03 +0100637 all_threads = {all_threads}
638 signum = {signum}
639 unregister = {unregister}
640 chain = {chain}
641 filename = {filename!r}
642 fd = {fd}
643
Victor Stinner6d201682014-08-10 19:50:08 +0200644 def func(signum):
645 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200646
Victor Stinner6d201682014-08-10 19:50:08 +0200647 def handler(signum, frame):
648 handler.called = True
649 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200650
Victor Stinner95bb7142015-03-12 15:32:03 +0100651 if filename:
652 file = open(filename, "wb")
653 elif fd is not None:
654 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200655 else:
656 file = None
657 if chain:
658 signal.signal(signum, handler)
659 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100660 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200661 if unregister:
662 faulthandler.unregister(signum)
663 func(signum)
664 if chain and not handler.called:
665 if file is not None:
666 output = file
667 else:
668 output = sys.stderr
669 print("Error: signal handler not called!", file=output)
670 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100671 else:
672 exitcode = 0
673 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200674 file.close()
675 sys.exit(exitcode)
676 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200677 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200678 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200679 signum=signum,
680 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200681 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100682 filename=filename,
683 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200684 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200685 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200686 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200687 if not unregister:
688 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400689 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200690 else:
R David Murray44b548d2016-09-08 13:59:53 -0400691 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100692 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200693 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200694 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200695 self.assertEqual(trace, '')
696 if unregister:
697 self.assertNotEqual(exitcode, 0)
698 else:
699 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200700
701 def test_register(self):
702 self.check_register()
703
Victor Stinnera01ca122011-04-01 12:56:17 +0200704 def test_unregister(self):
705 self.check_register(unregister=True)
706
Victor Stinner024e37a2011-03-31 01:31:06 +0200707 def test_register_file(self):
708 with temporary_filename() as filename:
709 self.check_register(filename=filename)
710
Victor Stinnerff2a6612015-03-13 11:01:30 +0100711 @unittest.skipIf(sys.platform == "win32",
712 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100713 def test_register_fd(self):
714 with tempfile.TemporaryFile('wb+') as fp:
715 self.check_register(fd=fp.fileno())
716
Victor Stinner024e37a2011-03-31 01:31:06 +0200717 def test_register_threads(self):
718 self.check_register(all_threads=True)
719
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200720 def test_register_chain(self):
721 self.check_register(chain=True)
722
Victor Stinnere2d66902014-05-14 17:15:50 +0200723 @contextmanager
724 def check_stderr_none(self):
725 stderr = sys.stderr
726 try:
727 sys.stderr = None
728 with self.assertRaises(RuntimeError) as cm:
729 yield
730 self.assertEqual(str(cm.exception), "sys.stderr is None")
731 finally:
732 sys.stderr = stderr
733
734 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300735 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200736 # instead of just an attribute error: "None has no attribute fileno".
737 with self.check_stderr_none():
738 faulthandler.enable()
739 with self.check_stderr_none():
740 faulthandler.dump_traceback()
741 if hasattr(faulthandler, 'dump_traceback_later'):
742 with self.check_stderr_none():
743 faulthandler.dump_traceback_later(1e-3)
744 if hasattr(faulthandler, "register"):
745 with self.check_stderr_none():
746 faulthandler.register(signal.SIGUSR1)
747
Victor Stinner937ee9e2018-06-26 02:11:06 +0200748 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100749 def test_raise_exception(self):
750 for exc, name in (
751 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
752 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
753 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
754 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400755 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100756 import faulthandler
757 faulthandler.enable()
758 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400759 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100760 3,
761 name)
762
Victor Stinner937ee9e2018-06-26 02:11:06 +0200763 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700764 def test_ignore_exception(self):
765 for exc_code in (
766 0xE06D7363, # MSC exception ("Emsc")
767 0xE0434352, # COM Callable Runtime exception ("ECCR")
768 ):
769 code = f"""
770 import faulthandler
771 faulthandler.enable()
772 faulthandler._raise_exception({exc_code})
773 """
774 code = dedent(code)
775 output, exitcode = self.get_output(code)
776 self.assertEqual(output, [])
777 self.assertEqual(exitcode, exc_code)
778
Victor Stinner937ee9e2018-06-26 02:11:06 +0200779 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700780 def test_raise_nonfatal_exception(self):
781 # These exceptions are not strictly errors. Letting
782 # faulthandler display the traceback when they are
783 # raised is likely to result in noise. However, they
784 # may still terminate the process if there is no
785 # handler installed for them (which there typically
786 # is, e.g. for debug messages).
787 for exc in (
788 0x00000000,
789 0x34567890,
790 0x40000000,
791 0x40001000,
792 0x70000000,
793 0x7FFFFFFF,
794 ):
795 output, exitcode = self.get_output(f"""
796 import faulthandler
797 faulthandler.enable()
798 faulthandler._raise_exception(0x{exc:x})
799 """
800 )
801 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200802 # On Windows older than 7 SP1, the actual exception code has
803 # bit 29 cleared.
804 self.assertIn(exitcode,
805 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700806
Victor Stinner937ee9e2018-06-26 02:11:06 +0200807 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200808 def test_disable_windows_exc_handler(self):
809 code = dedent("""
810 import faulthandler
811 faulthandler.enable()
812 faulthandler.disable()
813 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
814 faulthandler._raise_exception(code)
815 """)
816 output, exitcode = self.get_output(code)
817 self.assertEqual(output, [])
818 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100819
Thomas A Caswelle2783352019-08-29 12:30:04 -0400820 def test_cancel_later_without_dump_traceback_later(self):
821 # bpo-37933: Calling cancel_dump_traceback_later()
822 # without dump_traceback_later() must not segfault.
823 code = dedent("""
824 import faulthandler
825 faulthandler.cancel_dump_traceback_later()
826 """)
827 output, exitcode = self.get_output(code)
828 self.assertEqual(output, [])
829 self.assertEqual(exitcode, 0)
830
Victor Stinner024e37a2011-03-31 01:31:06 +0200831
Victor Stinner024e37a2011-03-31 01:31:06 +0200832if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400833 unittest.main()