blob: 80c1f7d90adf0fd07a74776b1a8d7911e697a13d [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
230 def test_fatal_error(self):
231 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200232 import faulthandler
233 faulthandler._fatal_error(b'xyz')
234 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200235 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200236 'xyz',
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100237 func='faulthandler_fatal_error_py',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200238 py_fatal_error=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200239
Victor Stinner57003f82016-03-15 17:23:35 +0100240 def test_fatal_error_without_gil(self):
241 self.check_fatal_error("""
242 import faulthandler
243 faulthandler._fatal_error(b'xyz', True)
244 """,
245 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200246 'xyz',
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100247 func='faulthandler_fatal_error_py',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200248 py_fatal_error=True)
Victor Stinner57003f82016-03-15 17:23:35 +0100249
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200250 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200251 "Issue #12868: sigaltstack() doesn't work on "
252 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200253 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
254 'need faulthandler._stack_overflow()')
255 def test_stack_overflow(self):
256 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200257 import faulthandler
258 faulthandler.enable()
259 faulthandler._stack_overflow()
260 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200261 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200262 '(?:Segmentation fault|Bus error)',
263 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200264
xdegayeef838062017-11-29 11:43:23 +0100265 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200266 def test_gil_released(self):
267 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200268 import faulthandler
269 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200270 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200271 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200272 3,
Victor Stinner50838282014-09-30 13:54:14 +0200273 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200274
Gregory P. Smith30e02322018-12-30 18:09:26 -0800275 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800276 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100277 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200278 def test_enable_file(self):
279 with temporary_filename() as filename:
280 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200281 import faulthandler
282 output = open({filename}, 'wb')
283 faulthandler.enable(output)
284 faulthandler._sigsegv()
285 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200286 4,
Victor Stinner56785392013-06-17 23:37:59 +0200287 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200288 filename=filename)
289
Victor Stinnerff2a6612015-03-13 11:01:30 +0100290 @unittest.skipIf(sys.platform == "win32",
291 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800292 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800293 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100294 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100295 def test_enable_fd(self):
296 with tempfile.TemporaryFile('wb+') as fp:
297 fd = fp.fileno()
298 self.check_fatal_error("""
299 import faulthandler
300 import sys
301 faulthandler.enable(%s)
302 faulthandler._sigsegv()
303 """ % fd,
304 4,
305 'Segmentation fault',
306 fd=fd)
307
xdegayeef838062017-11-29 11:43:23 +0100308 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200309 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200310 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200311 import faulthandler
312 faulthandler.enable(all_threads=False)
313 faulthandler._sigsegv()
314 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200315 3,
Victor Stinner56785392013-06-17 23:37:59 +0200316 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200317 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200318
xdegayeef838062017-11-29 11:43:23 +0100319 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200320 def test_disable(self):
321 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200322 import faulthandler
323 faulthandler.enable()
324 faulthandler.disable()
325 faulthandler._sigsegv()
326 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200327 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200328 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200329 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200330 self.assertTrue(not_expected not in stderr,
331 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200332 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200333
334 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200335 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200336 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200337 # regrtest may replace sys.stderr by io.StringIO object, but
338 # faulthandler.enable() requires that sys.stderr has a fileno()
339 # method
Victor Stinner72488502011-06-29 23:24:31 +0200340 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200341
342 was_enabled = faulthandler.is_enabled()
343 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200344 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200345 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200346 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200347 self.assertFalse(faulthandler.is_enabled())
348 finally:
349 if was_enabled:
350 faulthandler.enable()
351 else:
352 faulthandler.disable()
353 finally:
354 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200355
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200356 def test_disabled_by_default(self):
357 # By default, the module should be disabled
358 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100359 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800360 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100361 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200362 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200363
364 def test_sys_xoptions(self):
365 # Test python -X faulthandler
366 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800367 args = filter(None, (sys.executable,
368 "-E" if sys.flags.ignore_environment else "",
369 "-X", "faulthandler", "-c", code))
370 env = os.environ.copy()
371 env.pop("PYTHONFAULTHANDLER", None)
372 # don't use assert_python_ok() because it always enables faulthandler
373 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200374 self.assertEqual(output.rstrip(), b"True")
375
376 def test_env_var(self):
377 # empty env var
378 code = "import faulthandler; print(faulthandler.is_enabled())"
379 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100380 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200381 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100382 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800383 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200384 output = subprocess.check_output(args, env=env)
385 self.assertEqual(output.rstrip(), b"False")
386
387 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100388 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200389 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100390 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200391 output = subprocess.check_output(args, env=env)
392 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200393
Victor Stinner95bb7142015-03-12 15:32:03 +0100394 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200395 """
396 Explicitly call dump_traceback() function and check its output.
397 Raise an error if the output doesn't match the expected format.
398 """
399 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200400 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200401
Victor Stinner95bb7142015-03-12 15:32:03 +0100402 filename = {filename!r}
403 fd = {fd}
404
Victor Stinner6d201682014-08-10 19:50:08 +0200405 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100406 if filename:
407 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200408 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100409 elif fd is not None:
410 faulthandler.dump_traceback(fd,
411 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200412 else:
413 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200414
Victor Stinner6d201682014-08-10 19:50:08 +0200415 def funcA():
416 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200417
Victor Stinner6d201682014-08-10 19:50:08 +0200418 funcA()
419 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200420 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100421 filename=filename,
422 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200423 )
424 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100425 lineno = 9
426 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300427 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200428 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100429 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200430 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700431 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200432 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100433 ' File "<string>", line 17 in funcA',
434 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200435 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100436 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200437 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200438 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200439
440 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100441 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200442
443 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200444 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100445 self.check_dump_traceback(filename=filename)
446
Victor Stinnerff2a6612015-03-13 11:01:30 +0100447 @unittest.skipIf(sys.platform == "win32",
448 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100449 def test_dump_traceback_fd(self):
450 with tempfile.TemporaryFile('wb+') as fp:
451 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200452
Victor Stinner53386d82012-08-01 19:45:34 +0200453 def test_truncate(self):
454 maxlen = 500
455 func_name = 'x' * (maxlen + 50)
456 truncated = 'x' * maxlen + '...'
457 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200458 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200459
Victor Stinner6d201682014-08-10 19:50:08 +0200460 def {func_name}():
461 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200462
Victor Stinner6d201682014-08-10 19:50:08 +0200463 {func_name}()
464 """
Victor Stinner53386d82012-08-01 19:45:34 +0200465 code = code.format(
466 func_name=func_name,
467 )
468 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700469 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200470 ' File "<string>", line 4 in %s' % truncated,
471 ' File "<string>", line 6 in <module>'
472 ]
473 trace, exitcode = self.get_output(code)
474 self.assertEqual(trace, expected)
475 self.assertEqual(exitcode, 0)
476
Victor Stinner024e37a2011-03-31 01:31:06 +0200477 def check_dump_traceback_threads(self, filename):
478 """
479 Call explicitly dump_traceback(all_threads=True) and check the output.
480 Raise an error if the output doesn't match the expected format.
481 """
482 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200483 import faulthandler
484 from threading import Thread, Event
485 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200486
Victor Stinner6d201682014-08-10 19:50:08 +0200487 def dump():
488 if {filename}:
489 with open({filename}, "wb") as fp:
490 faulthandler.dump_traceback(fp, all_threads=True)
491 else:
492 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200493
Victor Stinner6d201682014-08-10 19:50:08 +0200494 class Waiter(Thread):
495 # avoid blocking if the main thread raises an exception.
496 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200497
Victor Stinner6d201682014-08-10 19:50:08 +0200498 def __init__(self):
499 Thread.__init__(self)
500 self.running = Event()
501 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200502
Victor Stinner6d201682014-08-10 19:50:08 +0200503 def run(self):
504 self.running.set()
505 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200506
Victor Stinner6d201682014-08-10 19:50:08 +0200507 waiter = Waiter()
508 waiter.start()
509 waiter.running.wait()
510 dump()
511 waiter.stop.set()
512 waiter.join()
513 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200514 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200515 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200516 output = '\n'.join(output)
517 if filename:
518 lineno = 8
519 else:
520 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400521 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200522 ^Thread 0x[0-9a-f]+ \(most recent call first\):
523 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
524 ){{1,3}} File "<string>", line 23 in run
525 File ".*threading.py", line [0-9]+ in _bootstrap_inner
526 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200527
Victor Stinner861d9ab2016-03-16 22:45:24 +0100528 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200529 File "<string>", line {lineno} in dump
530 File "<string>", line 28 in <module>$
531 """
532 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200533 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200534 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200535
536 def test_dump_traceback_threads(self):
537 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200538
539 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200540 with temporary_filename() as filename:
541 self.check_dump_traceback_threads(filename)
542
Victor Stinner95bb7142015-03-12 15:32:03 +0100543 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
544 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200545 """
546 Check how many times the traceback is written in timeout x 2.5 seconds,
547 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
548 on repeat and cancel options.
549
550 Raise an error if the output doesn't match the expect format.
551 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200552 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200553 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200554 import faulthandler
555 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100556 import sys
557
558 timeout = {timeout}
559 repeat = {repeat}
560 cancel = {cancel}
561 loops = {loops}
562 filename = {filename!r}
563 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200564
Victor Stinner6d201682014-08-10 19:50:08 +0200565 def func(timeout, repeat, cancel, file, loops):
566 for loop in range(loops):
567 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
568 if cancel:
569 faulthandler.cancel_dump_traceback_later()
570 time.sleep(timeout * 5)
571 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200572
Victor Stinner95bb7142015-03-12 15:32:03 +0100573 if filename:
574 file = open(filename, "wb")
575 elif fd is not None:
576 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200577 else:
578 file = None
579 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100580 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200581 file.close()
582 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200583 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200584 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200585 repeat=repeat,
586 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200587 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100588 filename=filename,
589 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200590 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200591 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200592 trace = '\n'.join(trace)
593
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200594 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200595 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200596 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200597 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700598 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100599 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200600 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200601 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200602 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200603 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200604
Georg Brandldeb92b52012-09-22 08:58:55 +0200605 def test_dump_traceback_later(self):
606 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200607
Georg Brandldeb92b52012-09-22 08:58:55 +0200608 def test_dump_traceback_later_repeat(self):
609 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200610
Georg Brandldeb92b52012-09-22 08:58:55 +0200611 def test_dump_traceback_later_cancel(self):
612 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200613
Georg Brandldeb92b52012-09-22 08:58:55 +0200614 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100615 with temporary_filename() as filename:
616 self.check_dump_traceback_later(filename=filename)
617
Victor Stinnerff2a6612015-03-13 11:01:30 +0100618 @unittest.skipIf(sys.platform == "win32",
619 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100620 def test_dump_traceback_later_fd(self):
621 with tempfile.TemporaryFile('wb+') as fp:
622 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200623
Georg Brandldeb92b52012-09-22 08:58:55 +0200624 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100625 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200626
Victor Stinner024e37a2011-03-31 01:31:06 +0200627 @unittest.skipIf(not hasattr(faulthandler, "register"),
628 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200629 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100630 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200631 """
632 Register a handler displaying the traceback on a user signal. Raise the
633 signal and check the written traceback.
634
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200635 If chain is True, check that the previous signal handler is called.
636
Victor Stinner024e37a2011-03-31 01:31:06 +0200637 Raise an error if the output doesn't match the expected format.
638 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200639 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200640 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200641 import faulthandler
642 import os
643 import signal
644 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200645
Victor Stinner95bb7142015-03-12 15:32:03 +0100646 all_threads = {all_threads}
647 signum = {signum}
648 unregister = {unregister}
649 chain = {chain}
650 filename = {filename!r}
651 fd = {fd}
652
Victor Stinner6d201682014-08-10 19:50:08 +0200653 def func(signum):
654 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200655
Victor Stinner6d201682014-08-10 19:50:08 +0200656 def handler(signum, frame):
657 handler.called = True
658 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200659
Victor Stinner95bb7142015-03-12 15:32:03 +0100660 if filename:
661 file = open(filename, "wb")
662 elif fd is not None:
663 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200664 else:
665 file = None
666 if chain:
667 signal.signal(signum, handler)
668 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100669 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200670 if unregister:
671 faulthandler.unregister(signum)
672 func(signum)
673 if chain and not handler.called:
674 if file is not None:
675 output = file
676 else:
677 output = sys.stderr
678 print("Error: signal handler not called!", file=output)
679 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100680 else:
681 exitcode = 0
682 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200683 file.close()
684 sys.exit(exitcode)
685 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200686 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200687 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200688 signum=signum,
689 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200690 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100691 filename=filename,
692 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200693 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200694 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200695 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200696 if not unregister:
697 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400698 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200699 else:
R David Murray44b548d2016-09-08 13:59:53 -0400700 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100701 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200702 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200703 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200704 self.assertEqual(trace, '')
705 if unregister:
706 self.assertNotEqual(exitcode, 0)
707 else:
708 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200709
710 def test_register(self):
711 self.check_register()
712
Victor Stinnera01ca122011-04-01 12:56:17 +0200713 def test_unregister(self):
714 self.check_register(unregister=True)
715
Victor Stinner024e37a2011-03-31 01:31:06 +0200716 def test_register_file(self):
717 with temporary_filename() as filename:
718 self.check_register(filename=filename)
719
Victor Stinnerff2a6612015-03-13 11:01:30 +0100720 @unittest.skipIf(sys.platform == "win32",
721 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100722 def test_register_fd(self):
723 with tempfile.TemporaryFile('wb+') as fp:
724 self.check_register(fd=fp.fileno())
725
Victor Stinner024e37a2011-03-31 01:31:06 +0200726 def test_register_threads(self):
727 self.check_register(all_threads=True)
728
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200729 def test_register_chain(self):
730 self.check_register(chain=True)
731
Victor Stinnere2d66902014-05-14 17:15:50 +0200732 @contextmanager
733 def check_stderr_none(self):
734 stderr = sys.stderr
735 try:
736 sys.stderr = None
737 with self.assertRaises(RuntimeError) as cm:
738 yield
739 self.assertEqual(str(cm.exception), "sys.stderr is None")
740 finally:
741 sys.stderr = stderr
742
743 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300744 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200745 # instead of just an attribute error: "None has no attribute fileno".
746 with self.check_stderr_none():
747 faulthandler.enable()
748 with self.check_stderr_none():
749 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200750 with self.check_stderr_none():
751 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200752 if hasattr(faulthandler, "register"):
753 with self.check_stderr_none():
754 faulthandler.register(signal.SIGUSR1)
755
Victor Stinner937ee9e2018-06-26 02:11:06 +0200756 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100757 def test_raise_exception(self):
758 for exc, name in (
759 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
760 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
761 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
762 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400763 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100764 import faulthandler
765 faulthandler.enable()
766 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400767 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100768 3,
769 name)
770
Victor Stinner937ee9e2018-06-26 02:11:06 +0200771 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700772 def test_ignore_exception(self):
773 for exc_code in (
774 0xE06D7363, # MSC exception ("Emsc")
775 0xE0434352, # COM Callable Runtime exception ("ECCR")
776 ):
777 code = f"""
778 import faulthandler
779 faulthandler.enable()
780 faulthandler._raise_exception({exc_code})
781 """
782 code = dedent(code)
783 output, exitcode = self.get_output(code)
784 self.assertEqual(output, [])
785 self.assertEqual(exitcode, exc_code)
786
Victor Stinner937ee9e2018-06-26 02:11:06 +0200787 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700788 def test_raise_nonfatal_exception(self):
789 # These exceptions are not strictly errors. Letting
790 # faulthandler display the traceback when they are
791 # raised is likely to result in noise. However, they
792 # may still terminate the process if there is no
793 # handler installed for them (which there typically
794 # is, e.g. for debug messages).
795 for exc in (
796 0x00000000,
797 0x34567890,
798 0x40000000,
799 0x40001000,
800 0x70000000,
801 0x7FFFFFFF,
802 ):
803 output, exitcode = self.get_output(f"""
804 import faulthandler
805 faulthandler.enable()
806 faulthandler._raise_exception(0x{exc:x})
807 """
808 )
809 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200810 # On Windows older than 7 SP1, the actual exception code has
811 # bit 29 cleared.
812 self.assertIn(exitcode,
813 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700814
Victor Stinner937ee9e2018-06-26 02:11:06 +0200815 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200816 def test_disable_windows_exc_handler(self):
817 code = dedent("""
818 import faulthandler
819 faulthandler.enable()
820 faulthandler.disable()
821 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
822 faulthandler._raise_exception(code)
823 """)
824 output, exitcode = self.get_output(code)
825 self.assertEqual(output, [])
826 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100827
Thomas A Caswelle2783352019-08-29 12:30:04 -0400828 def test_cancel_later_without_dump_traceback_later(self):
829 # bpo-37933: Calling cancel_dump_traceback_later()
830 # without dump_traceback_later() must not segfault.
831 code = dedent("""
832 import faulthandler
833 faulthandler.cancel_dump_traceback_later()
834 """)
835 output, exitcode = self.get_output(code)
836 self.assertEqual(output, [])
837 self.assertEqual(exitcode, 0)
838
Victor Stinner024e37a2011-03-31 01:31:06 +0200839
Victor Stinner024e37a2011-03-31 01:31:06 +0200840if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400841 unittest.main()