blob: bc61aab9c0fc26614f2e5975ace0785f797b4d33 [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
Hai Shi79bb2c92020-08-06 19:51:29 +080010from test.support import os_helper
Victor Stinner937ee9e2018-06-26 02:11:06 +020011from test.support import script_helper, is_android
Victor Stinner024e37a2011-03-31 01:31:06 +020012import tempfile
13import 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:
Hai Shi79bb2c92020-08-06 19:51:29 +080055 os_helper.unlink(filename)
Victor Stinner024e37a2011-03-31 01:31:06 +020056
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:
Victor Stinner6cac1132019-12-08 08:38:16 +010075 output, stderr = process.communicate()
Victor Stinner861d9ab2016-03-16 22:45:24 +010076 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020077 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020078 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020079 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020080 with open(filename, "rb") as fp:
81 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020082 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010083 elif fd is not None:
84 self.assertEqual(output, '')
85 os.lseek(fd, os.SEEK_SET, 0)
86 with open(fd, "rb", closefd=False) as fp:
87 output = fp.read()
88 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020089 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020090
Victor Stinner404cdc52016-03-23 10:39:17 +010091 def check_error(self, code, line_number, fatal_error, *,
92 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020093 fd=None, know_current_thread=True,
94 py_fatal_error=False):
Victor Stinner024e37a2011-03-31 01:31:06 +020095 """
96 Check that the fault handler for fatal errors is enabled and check the
97 traceback from the child process output.
98
99 Raise an error if the output doesn't match the expected format.
100 """
101 if all_threads:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100102 if know_current_thread:
103 header = 'Current thread 0x[0-9a-f]+'
104 else:
105 header = 'Thread 0x[0-9a-f]+'
Victor Stinner024e37a2011-03-31 01:31:06 +0200106 else:
Victor Stinner861d9ab2016-03-16 22:45:24 +0100107 header = 'Stack'
R David Murray44b548d2016-09-08 13:59:53 -0400108 regex = r"""
Gregory P. Smith30e02322018-12-30 18:09:26 -0800109 (?m)^{fatal_error}
Victor Stinner024e37a2011-03-31 01:31:06 +0200110
Victor Stinner861d9ab2016-03-16 22:45:24 +0100111 {header} \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200112 File "<string>", line {lineno} in <module>
113 """
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200114 if py_fatal_error:
115 fatal_error += "\nPython runtime state: initialized"
116 regex = dedent(regex).format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200117 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100118 fatal_error=fatal_error,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200119 header=header).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200120 if other_regex:
121 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100122 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200123 output = '\n'.join(output)
124 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200125 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200126
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100127 def check_fatal_error(self, code, line_number, name_regex, func=None, **kw):
128 if func:
129 name_regex = '%s: %s' % (func, name_regex)
Victor Stinner404cdc52016-03-23 10:39:17 +0100130 fatal_error = 'Fatal Python error: %s' % name_regex
131 self.check_error(code, line_number, fatal_error, **kw)
132
133 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100134 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100135 self.check_error(code, line_number, fatal_error, **kw)
136
Victor Stinner330426c2013-07-03 22:29:42 +0200137 @unittest.skipIf(sys.platform.startswith('aix'),
138 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200139 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200140 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100141 self.check_fatal_error("""
142 import faulthandler
143 faulthandler.enable()
144 faulthandler._read_null()
145 """,
146 3,
147 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
148 '(?:Segmentation fault'
149 '|Bus error'
150 '|Illegal instruction)')
151 else:
152 self.check_windows_exception("""
153 import faulthandler
154 faulthandler.enable()
155 faulthandler._read_null()
156 """,
157 3,
158 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200159
xdegayeef838062017-11-29 11:43:23 +0100160 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200161 def test_sigsegv(self):
162 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200163 import faulthandler
164 faulthandler.enable()
165 faulthandler._sigsegv()
166 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200167 3,
168 'Segmentation fault')
169
Victor Stinner861d9ab2016-03-16 22:45:24 +0100170 def test_fatal_error_c_thread(self):
171 self.check_fatal_error("""
172 import faulthandler
173 faulthandler.enable()
174 faulthandler._fatal_error_c_thread()
175 """,
176 3,
177 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200178 know_current_thread=False,
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100179 func='faulthandler_fatal_error_thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200180 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100181
Victor Stinnerd727e232011-04-01 12:13:55 +0200182 def test_sigabrt(self):
183 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200184 import faulthandler
185 faulthandler.enable()
186 faulthandler._sigabrt()
187 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200188 3,
189 'Aborted')
190
Victor Stinner024e37a2011-03-31 01:31:06 +0200191 @unittest.skipIf(sys.platform == 'win32',
192 "SIGFPE cannot be caught on Windows")
193 def test_sigfpe(self):
194 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200195 import faulthandler
196 faulthandler.enable()
197 faulthandler._sigfpe()
198 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200199 3,
200 'Floating point exception')
201
Victor Stinner56e8c292014-07-21 12:30:22 +0200202 @unittest.skipIf(_testcapi is None, 'need _testcapi')
203 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100204 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200205 def test_sigbus(self):
206 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200207 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200208 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200209
Victor Stinner6d201682014-08-10 19:50:08 +0200210 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800211 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200212 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800213 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200214 'Bus error')
215
Victor Stinner56e8c292014-07-21 12:30:22 +0200216 @unittest.skipIf(_testcapi is None, 'need _testcapi')
217 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100218 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200219 def test_sigill(self):
220 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200221 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200222 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200223
Victor Stinner6d201682014-08-10 19:50:08 +0200224 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800225 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200226 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800227 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200228 'Illegal instruction')
229
Victor Stinnere2320252021-01-18 18:24:29 +0100230 def check_fatal_error_func(self, release_gil):
231 # Test that Py_FatalError() dumps a traceback
232 with support.SuppressCrashReport():
233 self.check_fatal_error(f"""
234 import _testcapi
235 _testcapi.fatal_error(b'xyz', {release_gil})
236 """,
237 2,
238 'xyz',
239 func='test_fatal_error',
240 py_fatal_error=True)
241
Victor Stinner024e37a2011-03-31 01:31:06 +0200242 def test_fatal_error(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100243 self.check_fatal_error_func(False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200244
Victor Stinner57003f82016-03-15 17:23:35 +0100245 def test_fatal_error_without_gil(self):
Victor Stinnere2320252021-01-18 18:24:29 +0100246 self.check_fatal_error_func(True)
Victor Stinner57003f82016-03-15 17:23:35 +0100247
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200248 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200249 "Issue #12868: sigaltstack() doesn't work on "
250 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200251 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
252 'need faulthandler._stack_overflow()')
253 def test_stack_overflow(self):
254 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200255 import faulthandler
256 faulthandler.enable()
257 faulthandler._stack_overflow()
258 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200259 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200260 '(?:Segmentation fault|Bus error)',
261 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200262
xdegayeef838062017-11-29 11:43:23 +0100263 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200264 def test_gil_released(self):
265 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200266 import faulthandler
267 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200268 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200269 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200270 3,
Victor Stinner50838282014-09-30 13:54:14 +0200271 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200272
Gregory P. Smith30e02322018-12-30 18:09:26 -0800273 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800274 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100275 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200276 def test_enable_file(self):
277 with temporary_filename() as filename:
278 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200279 import faulthandler
280 output = open({filename}, 'wb')
281 faulthandler.enable(output)
282 faulthandler._sigsegv()
283 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200284 4,
Victor Stinner56785392013-06-17 23:37:59 +0200285 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200286 filename=filename)
287
Victor Stinnerff2a6612015-03-13 11:01:30 +0100288 @unittest.skipIf(sys.platform == "win32",
289 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800290 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800291 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100292 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100293 def test_enable_fd(self):
294 with tempfile.TemporaryFile('wb+') as fp:
295 fd = fp.fileno()
296 self.check_fatal_error("""
297 import faulthandler
298 import sys
299 faulthandler.enable(%s)
300 faulthandler._sigsegv()
301 """ % fd,
302 4,
303 'Segmentation fault',
304 fd=fd)
305
xdegayeef838062017-11-29 11:43:23 +0100306 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200307 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200308 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200309 import faulthandler
310 faulthandler.enable(all_threads=False)
311 faulthandler._sigsegv()
312 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200313 3,
Victor Stinner56785392013-06-17 23:37:59 +0200314 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200315 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200316
xdegayeef838062017-11-29 11:43:23 +0100317 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200318 def test_disable(self):
319 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200320 import faulthandler
321 faulthandler.enable()
322 faulthandler.disable()
323 faulthandler._sigsegv()
324 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200325 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200326 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200327 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200328 self.assertTrue(not_expected not in stderr,
329 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200330 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200331
332 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200333 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200334 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200335 # regrtest may replace sys.stderr by io.StringIO object, but
336 # faulthandler.enable() requires that sys.stderr has a fileno()
337 # method
Victor Stinner72488502011-06-29 23:24:31 +0200338 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200339
340 was_enabled = faulthandler.is_enabled()
341 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200342 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200343 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200344 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200345 self.assertFalse(faulthandler.is_enabled())
346 finally:
347 if was_enabled:
348 faulthandler.enable()
349 else:
350 faulthandler.disable()
351 finally:
352 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200353
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200354 def test_disabled_by_default(self):
355 # By default, the module should be disabled
356 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100357 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800358 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100359 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200360 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200361
362 def test_sys_xoptions(self):
363 # Test python -X faulthandler
364 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800365 args = filter(None, (sys.executable,
366 "-E" if sys.flags.ignore_environment else "",
367 "-X", "faulthandler", "-c", code))
368 env = os.environ.copy()
369 env.pop("PYTHONFAULTHANDLER", None)
370 # don't use assert_python_ok() because it always enables faulthandler
371 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200372 self.assertEqual(output.rstrip(), b"True")
373
374 def test_env_var(self):
375 # empty env var
376 code = "import faulthandler; print(faulthandler.is_enabled())"
377 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100378 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200379 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100380 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800381 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200382 output = subprocess.check_output(args, env=env)
383 self.assertEqual(output.rstrip(), b"False")
384
385 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100386 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200387 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100388 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200389 output = subprocess.check_output(args, env=env)
390 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200391
Victor Stinner95bb7142015-03-12 15:32:03 +0100392 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200393 """
394 Explicitly call dump_traceback() function and check its output.
395 Raise an error if the output doesn't match the expected format.
396 """
397 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200398 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200399
Victor Stinner95bb7142015-03-12 15:32:03 +0100400 filename = {filename!r}
401 fd = {fd}
402
Victor Stinner6d201682014-08-10 19:50:08 +0200403 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100404 if filename:
405 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200406 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100407 elif fd is not None:
408 faulthandler.dump_traceback(fd,
409 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200410 else:
411 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200412
Victor Stinner6d201682014-08-10 19:50:08 +0200413 def funcA():
414 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200415
Victor Stinner6d201682014-08-10 19:50:08 +0200416 funcA()
417 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200418 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100419 filename=filename,
420 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200421 )
422 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100423 lineno = 9
424 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300425 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200426 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100427 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200428 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700429 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200430 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100431 ' File "<string>", line 17 in funcA',
432 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200433 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100434 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200435 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200436 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200437
438 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100439 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200440
441 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200442 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100443 self.check_dump_traceback(filename=filename)
444
Victor Stinnerff2a6612015-03-13 11:01:30 +0100445 @unittest.skipIf(sys.platform == "win32",
446 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100447 def test_dump_traceback_fd(self):
448 with tempfile.TemporaryFile('wb+') as fp:
449 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200450
Victor Stinner53386d82012-08-01 19:45:34 +0200451 def test_truncate(self):
452 maxlen = 500
453 func_name = 'x' * (maxlen + 50)
454 truncated = 'x' * maxlen + '...'
455 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200456 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200457
Victor Stinner6d201682014-08-10 19:50:08 +0200458 def {func_name}():
459 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200460
Victor Stinner6d201682014-08-10 19:50:08 +0200461 {func_name}()
462 """
Victor Stinner53386d82012-08-01 19:45:34 +0200463 code = code.format(
464 func_name=func_name,
465 )
466 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700467 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200468 ' File "<string>", line 4 in %s' % truncated,
469 ' File "<string>", line 6 in <module>'
470 ]
471 trace, exitcode = self.get_output(code)
472 self.assertEqual(trace, expected)
473 self.assertEqual(exitcode, 0)
474
Victor Stinner024e37a2011-03-31 01:31:06 +0200475 def check_dump_traceback_threads(self, filename):
476 """
477 Call explicitly dump_traceback(all_threads=True) and check the output.
478 Raise an error if the output doesn't match the expected format.
479 """
480 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200481 import faulthandler
482 from threading import Thread, Event
483 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200484
Victor Stinner6d201682014-08-10 19:50:08 +0200485 def dump():
486 if {filename}:
487 with open({filename}, "wb") as fp:
488 faulthandler.dump_traceback(fp, all_threads=True)
489 else:
490 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200491
Victor Stinner6d201682014-08-10 19:50:08 +0200492 class Waiter(Thread):
493 # avoid blocking if the main thread raises an exception.
494 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200495
Victor Stinner6d201682014-08-10 19:50:08 +0200496 def __init__(self):
497 Thread.__init__(self)
498 self.running = Event()
499 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200500
Victor Stinner6d201682014-08-10 19:50:08 +0200501 def run(self):
502 self.running.set()
503 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200504
Victor Stinner6d201682014-08-10 19:50:08 +0200505 waiter = Waiter()
506 waiter.start()
507 waiter.running.wait()
508 dump()
509 waiter.stop.set()
510 waiter.join()
511 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200512 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200513 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200514 output = '\n'.join(output)
515 if filename:
516 lineno = 8
517 else:
518 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400519 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200520 ^Thread 0x[0-9a-f]+ \(most recent call first\):
521 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
522 ){{1,3}} File "<string>", line 23 in run
523 File ".*threading.py", line [0-9]+ in _bootstrap_inner
524 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200525
Victor Stinner861d9ab2016-03-16 22:45:24 +0100526 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200527 File "<string>", line {lineno} in dump
528 File "<string>", line 28 in <module>$
529 """
530 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200531 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200532 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200533
534 def test_dump_traceback_threads(self):
535 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200536
537 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200538 with temporary_filename() as filename:
539 self.check_dump_traceback_threads(filename)
540
Victor Stinner95bb7142015-03-12 15:32:03 +0100541 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
542 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200543 """
544 Check how many times the traceback is written in timeout x 2.5 seconds,
545 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
546 on repeat and cancel options.
547
548 Raise an error if the output doesn't match the expect format.
549 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200550 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200551 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200552 import faulthandler
553 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100554 import sys
555
556 timeout = {timeout}
557 repeat = {repeat}
558 cancel = {cancel}
559 loops = {loops}
560 filename = {filename!r}
561 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200562
Victor Stinner6d201682014-08-10 19:50:08 +0200563 def func(timeout, repeat, cancel, file, loops):
564 for loop in range(loops):
565 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
566 if cancel:
567 faulthandler.cancel_dump_traceback_later()
568 time.sleep(timeout * 5)
569 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200570
Victor Stinner95bb7142015-03-12 15:32:03 +0100571 if filename:
572 file = open(filename, "wb")
573 elif fd is not None:
574 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200575 else:
576 file = None
577 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100578 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200579 file.close()
580 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200581 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200582 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200583 repeat=repeat,
584 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200585 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100586 filename=filename,
587 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200588 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200589 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200590 trace = '\n'.join(trace)
591
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200592 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200593 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200594 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200595 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700596 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100597 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200598 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200599 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200600 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200601 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200602
Georg Brandldeb92b52012-09-22 08:58:55 +0200603 def test_dump_traceback_later(self):
604 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200605
Georg Brandldeb92b52012-09-22 08:58:55 +0200606 def test_dump_traceback_later_repeat(self):
607 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200608
Georg Brandldeb92b52012-09-22 08:58:55 +0200609 def test_dump_traceback_later_cancel(self):
610 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200611
Georg Brandldeb92b52012-09-22 08:58:55 +0200612 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100613 with temporary_filename() as filename:
614 self.check_dump_traceback_later(filename=filename)
615
Victor Stinnerff2a6612015-03-13 11:01:30 +0100616 @unittest.skipIf(sys.platform == "win32",
617 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100618 def test_dump_traceback_later_fd(self):
619 with tempfile.TemporaryFile('wb+') as fp:
620 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200621
Georg Brandldeb92b52012-09-22 08:58:55 +0200622 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100623 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200624
Victor Stinner024e37a2011-03-31 01:31:06 +0200625 @unittest.skipIf(not hasattr(faulthandler, "register"),
626 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200627 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100628 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200629 """
630 Register a handler displaying the traceback on a user signal. Raise the
631 signal and check the written traceback.
632
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200633 If chain is True, check that the previous signal handler is called.
634
Victor Stinner024e37a2011-03-31 01:31:06 +0200635 Raise an error if the output doesn't match the expected format.
636 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200637 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200638 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200639 import faulthandler
640 import os
641 import signal
642 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200643
Victor Stinner95bb7142015-03-12 15:32:03 +0100644 all_threads = {all_threads}
645 signum = {signum}
646 unregister = {unregister}
647 chain = {chain}
648 filename = {filename!r}
649 fd = {fd}
650
Victor Stinner6d201682014-08-10 19:50:08 +0200651 def func(signum):
652 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200653
Victor Stinner6d201682014-08-10 19:50:08 +0200654 def handler(signum, frame):
655 handler.called = True
656 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200657
Victor Stinner95bb7142015-03-12 15:32:03 +0100658 if filename:
659 file = open(filename, "wb")
660 elif fd is not None:
661 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200662 else:
663 file = None
664 if chain:
665 signal.signal(signum, handler)
666 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100667 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200668 if unregister:
669 faulthandler.unregister(signum)
670 func(signum)
671 if chain and not handler.called:
672 if file is not None:
673 output = file
674 else:
675 output = sys.stderr
676 print("Error: signal handler not called!", file=output)
677 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100678 else:
679 exitcode = 0
680 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200681 file.close()
682 sys.exit(exitcode)
683 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200684 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200685 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200686 signum=signum,
687 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200688 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100689 filename=filename,
690 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200691 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200692 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200693 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200694 if not unregister:
695 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400696 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200697 else:
R David Murray44b548d2016-09-08 13:59:53 -0400698 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100699 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200700 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200701 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200702 self.assertEqual(trace, '')
703 if unregister:
704 self.assertNotEqual(exitcode, 0)
705 else:
706 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200707
708 def test_register(self):
709 self.check_register()
710
Victor Stinnera01ca122011-04-01 12:56:17 +0200711 def test_unregister(self):
712 self.check_register(unregister=True)
713
Victor Stinner024e37a2011-03-31 01:31:06 +0200714 def test_register_file(self):
715 with temporary_filename() as filename:
716 self.check_register(filename=filename)
717
Victor Stinnerff2a6612015-03-13 11:01:30 +0100718 @unittest.skipIf(sys.platform == "win32",
719 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100720 def test_register_fd(self):
721 with tempfile.TemporaryFile('wb+') as fp:
722 self.check_register(fd=fp.fileno())
723
Victor Stinner024e37a2011-03-31 01:31:06 +0200724 def test_register_threads(self):
725 self.check_register(all_threads=True)
726
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200727 def test_register_chain(self):
728 self.check_register(chain=True)
729
Victor Stinnere2d66902014-05-14 17:15:50 +0200730 @contextmanager
731 def check_stderr_none(self):
732 stderr = sys.stderr
733 try:
734 sys.stderr = None
735 with self.assertRaises(RuntimeError) as cm:
736 yield
737 self.assertEqual(str(cm.exception), "sys.stderr is None")
738 finally:
739 sys.stderr = stderr
740
741 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300742 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200743 # instead of just an attribute error: "None has no attribute fileno".
744 with self.check_stderr_none():
745 faulthandler.enable()
746 with self.check_stderr_none():
747 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200748 with self.check_stderr_none():
749 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200750 if hasattr(faulthandler, "register"):
751 with self.check_stderr_none():
752 faulthandler.register(signal.SIGUSR1)
753
Victor Stinner937ee9e2018-06-26 02:11:06 +0200754 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100755 def test_raise_exception(self):
756 for exc, name in (
757 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
758 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
759 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
760 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400761 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100762 import faulthandler
763 faulthandler.enable()
764 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400765 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100766 3,
767 name)
768
Victor Stinner937ee9e2018-06-26 02:11:06 +0200769 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700770 def test_ignore_exception(self):
771 for exc_code in (
772 0xE06D7363, # MSC exception ("Emsc")
773 0xE0434352, # COM Callable Runtime exception ("ECCR")
774 ):
775 code = f"""
776 import faulthandler
777 faulthandler.enable()
778 faulthandler._raise_exception({exc_code})
779 """
780 code = dedent(code)
781 output, exitcode = self.get_output(code)
782 self.assertEqual(output, [])
783 self.assertEqual(exitcode, exc_code)
784
Victor Stinner937ee9e2018-06-26 02:11:06 +0200785 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700786 def test_raise_nonfatal_exception(self):
787 # These exceptions are not strictly errors. Letting
788 # faulthandler display the traceback when they are
789 # raised is likely to result in noise. However, they
790 # may still terminate the process if there is no
791 # handler installed for them (which there typically
792 # is, e.g. for debug messages).
793 for exc in (
794 0x00000000,
795 0x34567890,
796 0x40000000,
797 0x40001000,
798 0x70000000,
799 0x7FFFFFFF,
800 ):
801 output, exitcode = self.get_output(f"""
802 import faulthandler
803 faulthandler.enable()
804 faulthandler._raise_exception(0x{exc:x})
805 """
806 )
807 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200808 # On Windows older than 7 SP1, the actual exception code has
809 # bit 29 cleared.
810 self.assertIn(exitcode,
811 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700812
Victor Stinner937ee9e2018-06-26 02:11:06 +0200813 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200814 def test_disable_windows_exc_handler(self):
815 code = dedent("""
816 import faulthandler
817 faulthandler.enable()
818 faulthandler.disable()
819 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
820 faulthandler._raise_exception(code)
821 """)
822 output, exitcode = self.get_output(code)
823 self.assertEqual(output, [])
824 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100825
Thomas A Caswelle2783352019-08-29 12:30:04 -0400826 def test_cancel_later_without_dump_traceback_later(self):
827 # bpo-37933: Calling cancel_dump_traceback_later()
828 # without dump_traceback_later() must not segfault.
829 code = dedent("""
830 import faulthandler
831 faulthandler.cancel_dump_traceback_later()
832 """)
833 output, exitcode = self.get_output(code)
834 self.assertEqual(output, [])
835 self.assertEqual(exitcode, 0)
836
Victor Stinner024e37a2011-03-31 01:31:06 +0200837
Victor Stinner024e37a2011-03-31 01:31:06 +0200838if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400839 unittest.main()