blob: c64afe88c25d6c0c7453fa939128f3be5216fc41 [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:
Victor Stinner6cac1132019-12-08 08:38:16 +010074 output, stderr = process.communicate()
Victor Stinner861d9ab2016-03-16 22:45:24 +010075 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020076 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020077 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020078 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020079 with open(filename, "rb") as fp:
80 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020081 output = output.decode('ascii', 'backslashreplace')
Victor Stinner95bb7142015-03-12 15:32:03 +010082 elif fd is not None:
83 self.assertEqual(output, '')
84 os.lseek(fd, os.SEEK_SET, 0)
85 with open(fd, "rb", closefd=False) as fp:
86 output = fp.read()
87 output = output.decode('ascii', 'backslashreplace')
Victor Stinner05585cb2011-03-31 13:29:56 +020088 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020089
Victor Stinner404cdc52016-03-23 10:39:17 +010090 def check_error(self, code, line_number, fatal_error, *,
91 filename=None, all_threads=True, other_regex=None,
Victor Stinner1ce16fb2019-09-18 01:35:33 +020092 fd=None, know_current_thread=True,
93 py_fatal_error=False):
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 """
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200113 if py_fatal_error:
114 fatal_error += "\nPython runtime state: initialized"
115 regex = dedent(regex).format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200116 lineno=line_number,
Victor Stinner404cdc52016-03-23 10:39:17 +0100117 fatal_error=fatal_error,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200118 header=header).strip()
Victor Stinnerf0480752011-03-31 11:34:08 +0200119 if other_regex:
120 regex += '|' + other_regex
Victor Stinner95bb7142015-03-12 15:32:03 +0100121 output, exitcode = self.get_output(code, filename=filename, fd=fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200122 output = '\n'.join(output)
123 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200124 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200125
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100126 def check_fatal_error(self, code, line_number, name_regex, func=None, **kw):
127 if func:
128 name_regex = '%s: %s' % (func, name_regex)
Victor Stinner404cdc52016-03-23 10:39:17 +0100129 fatal_error = 'Fatal Python error: %s' % name_regex
130 self.check_error(code, line_number, fatal_error, **kw)
131
132 def check_windows_exception(self, code, line_number, name_regex, **kw):
Victor Stinner412a5e72016-03-23 14:44:14 +0100133 fatal_error = 'Windows fatal exception: %s' % name_regex
Victor Stinner404cdc52016-03-23 10:39:17 +0100134 self.check_error(code, line_number, fatal_error, **kw)
135
Victor Stinner330426c2013-07-03 22:29:42 +0200136 @unittest.skipIf(sys.platform.startswith('aix'),
137 "the first page of memory is a mapped read-only on AIX")
Victor Stinner024e37a2011-03-31 01:31:06 +0200138 def test_read_null(self):
Victor Stinner937ee9e2018-06-26 02:11:06 +0200139 if not MS_WINDOWS:
Victor Stinner404cdc52016-03-23 10:39:17 +0100140 self.check_fatal_error("""
141 import faulthandler
142 faulthandler.enable()
143 faulthandler._read_null()
144 """,
145 3,
146 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
147 '(?:Segmentation fault'
148 '|Bus error'
149 '|Illegal instruction)')
150 else:
151 self.check_windows_exception("""
152 import faulthandler
153 faulthandler.enable()
154 faulthandler._read_null()
155 """,
156 3,
157 'access violation')
Victor Stinner024e37a2011-03-31 01:31:06 +0200158
xdegayeef838062017-11-29 11:43:23 +0100159 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200160 def test_sigsegv(self):
161 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200162 import faulthandler
163 faulthandler.enable()
164 faulthandler._sigsegv()
165 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200166 3,
167 'Segmentation fault')
168
Victor Stinner861d9ab2016-03-16 22:45:24 +0100169 def test_fatal_error_c_thread(self):
170 self.check_fatal_error("""
171 import faulthandler
172 faulthandler.enable()
173 faulthandler._fatal_error_c_thread()
174 """,
175 3,
176 'in new thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200177 know_current_thread=False,
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100178 func='faulthandler_fatal_error_thread',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200179 py_fatal_error=True)
Victor Stinner861d9ab2016-03-16 22:45:24 +0100180
Victor Stinnerd727e232011-04-01 12:13:55 +0200181 def test_sigabrt(self):
182 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200183 import faulthandler
184 faulthandler.enable()
185 faulthandler._sigabrt()
186 """,
Victor Stinnerd727e232011-04-01 12:13:55 +0200187 3,
188 'Aborted')
189
Victor Stinner024e37a2011-03-31 01:31:06 +0200190 @unittest.skipIf(sys.platform == 'win32',
191 "SIGFPE cannot be caught on Windows")
192 def test_sigfpe(self):
193 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200194 import faulthandler
195 faulthandler.enable()
196 faulthandler._sigfpe()
197 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200198 3,
199 'Floating point exception')
200
Victor Stinner56e8c292014-07-21 12:30:22 +0200201 @unittest.skipIf(_testcapi is None, 'need _testcapi')
202 @unittest.skipUnless(hasattr(signal, 'SIGBUS'), 'need signal.SIGBUS')
xdegayeef838062017-11-29 11:43:23 +0100203 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200204 def test_sigbus(self):
205 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200206 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200207 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200208
Victor Stinner6d201682014-08-10 19:50:08 +0200209 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800210 signal.raise_signal(signal.SIGBUS)
Victor Stinner6d201682014-08-10 19:50:08 +0200211 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800212 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200213 'Bus error')
214
Victor Stinner56e8c292014-07-21 12:30:22 +0200215 @unittest.skipIf(_testcapi is None, 'need _testcapi')
216 @unittest.skipUnless(hasattr(signal, 'SIGILL'), 'need signal.SIGILL')
xdegayeef838062017-11-29 11:43:23 +0100217 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200218 def test_sigill(self):
219 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200220 import faulthandler
Victor Stinner68e08082014-08-10 19:51:05 +0200221 import signal
Victor Stinner56e8c292014-07-21 12:30:22 +0200222
Victor Stinner6d201682014-08-10 19:50:08 +0200223 faulthandler.enable()
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800224 signal.raise_signal(signal.SIGILL)
Victor Stinner6d201682014-08-10 19:50:08 +0200225 """,
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800226 5,
Victor Stinner024e37a2011-03-31 01:31:06 +0200227 'Illegal instruction')
228
229 def test_fatal_error(self):
230 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200231 import faulthandler
232 faulthandler._fatal_error(b'xyz')
233 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200234 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200235 'xyz',
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100236 func='faulthandler_fatal_error_py',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200237 py_fatal_error=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200238
Victor Stinner57003f82016-03-15 17:23:35 +0100239 def test_fatal_error_without_gil(self):
240 self.check_fatal_error("""
241 import faulthandler
242 faulthandler._fatal_error(b'xyz', True)
243 """,
244 2,
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200245 'xyz',
Victor Stinner9e5d30c2020-03-07 00:54:20 +0100246 func='faulthandler_fatal_error_py',
Victor Stinner1ce16fb2019-09-18 01:35:33 +0200247 py_fatal_error=True)
Victor Stinner57003f82016-03-15 17:23:35 +0100248
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200249 @unittest.skipIf(sys.platform.startswith('openbsd'),
Charles-François Natali3391e642011-09-01 23:08:21 +0200250 "Issue #12868: sigaltstack() doesn't work on "
251 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200252 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
253 'need faulthandler._stack_overflow()')
254 def test_stack_overflow(self):
255 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200256 import faulthandler
257 faulthandler.enable()
258 faulthandler._stack_overflow()
259 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200260 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200261 '(?:Segmentation fault|Bus error)',
262 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200263
xdegayeef838062017-11-29 11:43:23 +0100264 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200265 def test_gil_released(self):
266 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200267 import faulthandler
268 faulthandler.enable()
Victor Stinner50838282014-09-30 13:54:14 +0200269 faulthandler._sigsegv(True)
Victor Stinner6d201682014-08-10 19:50:08 +0200270 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200271 3,
Victor Stinner50838282014-09-30 13:54:14 +0200272 'Segmentation fault')
Victor Stinner024e37a2011-03-31 01:31:06 +0200273
Gregory P. Smith30e02322018-12-30 18:09:26 -0800274 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800275 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100276 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200277 def test_enable_file(self):
278 with temporary_filename() as filename:
279 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200280 import faulthandler
281 output = open({filename}, 'wb')
282 faulthandler.enable(output)
283 faulthandler._sigsegv()
284 """.format(filename=repr(filename)),
Victor Stinner024e37a2011-03-31 01:31:06 +0200285 4,
Victor Stinner56785392013-06-17 23:37:59 +0200286 'Segmentation fault',
Victor Stinner024e37a2011-03-31 01:31:06 +0200287 filename=filename)
288
Victor Stinnerff2a6612015-03-13 11:01:30 +0100289 @unittest.skipIf(sys.platform == "win32",
290 "subprocess doesn't support pass_fds on Windows")
Gregory P. Smith30e02322018-12-30 18:09:26 -0800291 @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
Gregory P. Smithd6f45b22018-12-30 20:15:41 -0800292 "sanitizer builds change crashing process output.")
xdegayeef838062017-11-29 11:43:23 +0100293 @skip_segfault_on_android
Victor Stinner95bb7142015-03-12 15:32:03 +0100294 def test_enable_fd(self):
295 with tempfile.TemporaryFile('wb+') as fp:
296 fd = fp.fileno()
297 self.check_fatal_error("""
298 import faulthandler
299 import sys
300 faulthandler.enable(%s)
301 faulthandler._sigsegv()
302 """ % fd,
303 4,
304 'Segmentation fault',
305 fd=fd)
306
xdegayeef838062017-11-29 11:43:23 +0100307 @skip_segfault_on_android
Victor Stinner7bba62f2011-05-07 12:43:00 +0200308 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 self.check_fatal_error("""
Victor Stinner6d201682014-08-10 19:50:08 +0200310 import faulthandler
311 faulthandler.enable(all_threads=False)
312 faulthandler._sigsegv()
313 """,
Victor Stinner024e37a2011-03-31 01:31:06 +0200314 3,
Victor Stinner56785392013-06-17 23:37:59 +0200315 'Segmentation fault',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200316 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200317
xdegayeef838062017-11-29 11:43:23 +0100318 @skip_segfault_on_android
Victor Stinner024e37a2011-03-31 01:31:06 +0200319 def test_disable(self):
320 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200321 import faulthandler
322 faulthandler.enable()
323 faulthandler.disable()
324 faulthandler._sigsegv()
325 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200326 not_expected = 'Fatal Python error'
Antoine Pitrou77e904e2013-10-08 23:04:32 +0200327 stderr, exitcode = self.get_output(code)
Victor Stinner29001c82014-09-25 00:38:48 +0200328 stderr = '\n'.join(stderr)
Victor Stinner024e37a2011-03-31 01:31:06 +0200329 self.assertTrue(not_expected not in stderr,
330 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200331 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200332
333 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200334 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200335 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200336 # regrtest may replace sys.stderr by io.StringIO object, but
337 # faulthandler.enable() requires that sys.stderr has a fileno()
338 # method
Victor Stinner72488502011-06-29 23:24:31 +0200339 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200340
341 was_enabled = faulthandler.is_enabled()
342 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200343 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200344 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200345 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200346 self.assertFalse(faulthandler.is_enabled())
347 finally:
348 if was_enabled:
349 faulthandler.enable()
350 else:
351 faulthandler.disable()
352 finally:
353 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200354
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200355 def test_disabled_by_default(self):
356 # By default, the module should be disabled
357 code = "import faulthandler; print(faulthandler.is_enabled())"
Victor Stinner721e25c2017-12-12 23:15:00 +0100358 args = (sys.executable, "-E", "-c", code)
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800359 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner721e25c2017-12-12 23:15:00 +0100360 output = subprocess.check_output(args)
Victor Stinner88983502013-09-08 11:36:23 +0200361 self.assertEqual(output.rstrip(), b"False")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200362
363 def test_sys_xoptions(self):
364 # Test python -X faulthandler
365 code = "import faulthandler; print(faulthandler.is_enabled())"
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800366 args = filter(None, (sys.executable,
367 "-E" if sys.flags.ignore_environment else "",
368 "-X", "faulthandler", "-c", code))
369 env = os.environ.copy()
370 env.pop("PYTHONFAULTHANDLER", None)
371 # don't use assert_python_ok() because it always enables faulthandler
372 output = subprocess.check_output(args, env=env)
Victor Stinner88983502013-09-08 11:36:23 +0200373 self.assertEqual(output.rstrip(), b"True")
374
375 def test_env_var(self):
376 # empty env var
377 code = "import faulthandler; print(faulthandler.is_enabled())"
378 args = (sys.executable, "-c", code)
Victor Stinner721e25c2017-12-12 23:15:00 +0100379 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200380 env['PYTHONFAULTHANDLER'] = ''
Victor Stinner721e25c2017-12-12 23:15:00 +0100381 env['PYTHONDEVMODE'] = ''
Gregory P. Smithfe7c5d62015-01-22 17:33:28 -0800382 # don't use assert_python_ok() because it always enables faulthandler
Victor Stinner88983502013-09-08 11:36:23 +0200383 output = subprocess.check_output(args, env=env)
384 self.assertEqual(output.rstrip(), b"False")
385
386 # non-empty env var
Victor Stinner721e25c2017-12-12 23:15:00 +0100387 env = dict(os.environ)
Victor Stinner88983502013-09-08 11:36:23 +0200388 env['PYTHONFAULTHANDLER'] = '1'
Victor Stinner721e25c2017-12-12 23:15:00 +0100389 env['PYTHONDEVMODE'] = ''
Victor Stinner88983502013-09-08 11:36:23 +0200390 output = subprocess.check_output(args, env=env)
391 self.assertEqual(output.rstrip(), b"True")
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200392
Victor Stinner95bb7142015-03-12 15:32:03 +0100393 def check_dump_traceback(self, *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200394 """
395 Explicitly call dump_traceback() function and check its output.
396 Raise an error if the output doesn't match the expected format.
397 """
398 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200399 import faulthandler
Victor Stinner024e37a2011-03-31 01:31:06 +0200400
Victor Stinner95bb7142015-03-12 15:32:03 +0100401 filename = {filename!r}
402 fd = {fd}
403
Victor Stinner6d201682014-08-10 19:50:08 +0200404 def funcB():
Victor Stinner95bb7142015-03-12 15:32:03 +0100405 if filename:
406 with open(filename, "wb") as fp:
Victor Stinner6d201682014-08-10 19:50:08 +0200407 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner95bb7142015-03-12 15:32:03 +0100408 elif fd is not None:
409 faulthandler.dump_traceback(fd,
410 all_threads=False)
Victor Stinner6d201682014-08-10 19:50:08 +0200411 else:
412 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200413
Victor Stinner6d201682014-08-10 19:50:08 +0200414 def funcA():
415 funcB()
Victor Stinner024e37a2011-03-31 01:31:06 +0200416
Victor Stinner6d201682014-08-10 19:50:08 +0200417 funcA()
418 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200419 code = code.format(
Victor Stinner95bb7142015-03-12 15:32:03 +0100420 filename=filename,
421 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200422 )
423 if filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100424 lineno = 9
425 elif fd is not None:
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300426 lineno = 11
Victor Stinner024e37a2011-03-31 01:31:06 +0200427 else:
Victor Stinner95bb7142015-03-12 15:32:03 +0100428 lineno = 14
Victor Stinner024e37a2011-03-31 01:31:06 +0200429 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700430 'Stack (most recent call first):',
Victor Stinner024e37a2011-03-31 01:31:06 +0200431 ' File "<string>", line %s in funcB' % lineno,
Victor Stinner95bb7142015-03-12 15:32:03 +0100432 ' File "<string>", line 17 in funcA',
433 ' File "<string>", line 19 in <module>'
Victor Stinner024e37a2011-03-31 01:31:06 +0200434 ]
Victor Stinner95bb7142015-03-12 15:32:03 +0100435 trace, exitcode = self.get_output(code, filename, fd)
Victor Stinner024e37a2011-03-31 01:31:06 +0200436 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200437 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200438
439 def test_dump_traceback(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100440 self.check_dump_traceback()
Victor Stinner19402332011-03-31 18:15:52 +0200441
442 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200443 with temporary_filename() as filename:
Victor Stinner95bb7142015-03-12 15:32:03 +0100444 self.check_dump_traceback(filename=filename)
445
Victor Stinnerff2a6612015-03-13 11:01:30 +0100446 @unittest.skipIf(sys.platform == "win32",
447 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100448 def test_dump_traceback_fd(self):
449 with tempfile.TemporaryFile('wb+') as fp:
450 self.check_dump_traceback(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200451
Victor Stinner53386d82012-08-01 19:45:34 +0200452 def test_truncate(self):
453 maxlen = 500
454 func_name = 'x' * (maxlen + 50)
455 truncated = 'x' * maxlen + '...'
456 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200457 import faulthandler
Victor Stinner53386d82012-08-01 19:45:34 +0200458
Victor Stinner6d201682014-08-10 19:50:08 +0200459 def {func_name}():
460 faulthandler.dump_traceback(all_threads=False)
Victor Stinner53386d82012-08-01 19:45:34 +0200461
Victor Stinner6d201682014-08-10 19:50:08 +0200462 {func_name}()
463 """
Victor Stinner53386d82012-08-01 19:45:34 +0200464 code = code.format(
465 func_name=func_name,
466 )
467 expected = [
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700468 'Stack (most recent call first):',
Victor Stinner53386d82012-08-01 19:45:34 +0200469 ' File "<string>", line 4 in %s' % truncated,
470 ' File "<string>", line 6 in <module>'
471 ]
472 trace, exitcode = self.get_output(code)
473 self.assertEqual(trace, expected)
474 self.assertEqual(exitcode, 0)
475
Victor Stinner024e37a2011-03-31 01:31:06 +0200476 def check_dump_traceback_threads(self, filename):
477 """
478 Call explicitly dump_traceback(all_threads=True) and check the output.
479 Raise an error if the output doesn't match the expected format.
480 """
481 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200482 import faulthandler
483 from threading import Thread, Event
484 import time
Victor Stinner024e37a2011-03-31 01:31:06 +0200485
Victor Stinner6d201682014-08-10 19:50:08 +0200486 def dump():
487 if {filename}:
488 with open({filename}, "wb") as fp:
489 faulthandler.dump_traceback(fp, all_threads=True)
490 else:
491 faulthandler.dump_traceback(all_threads=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200492
Victor Stinner6d201682014-08-10 19:50:08 +0200493 class Waiter(Thread):
494 # avoid blocking if the main thread raises an exception.
495 daemon = True
Victor Stinner024e37a2011-03-31 01:31:06 +0200496
Victor Stinner6d201682014-08-10 19:50:08 +0200497 def __init__(self):
498 Thread.__init__(self)
499 self.running = Event()
500 self.stop = Event()
Victor Stinner024e37a2011-03-31 01:31:06 +0200501
Victor Stinner6d201682014-08-10 19:50:08 +0200502 def run(self):
503 self.running.set()
504 self.stop.wait()
Victor Stinner024e37a2011-03-31 01:31:06 +0200505
Victor Stinner6d201682014-08-10 19:50:08 +0200506 waiter = Waiter()
507 waiter.start()
508 waiter.running.wait()
509 dump()
510 waiter.stop.set()
511 waiter.join()
512 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200513 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200514 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200515 output = '\n'.join(output)
516 if filename:
517 lineno = 8
518 else:
519 lineno = 10
R David Murray44b548d2016-09-08 13:59:53 -0400520 regex = r"""
Victor Stinner6d201682014-08-10 19:50:08 +0200521 ^Thread 0x[0-9a-f]+ \(most recent call first\):
522 (?: File ".*threading.py", line [0-9]+ in [_a-z]+
523 ){{1,3}} File "<string>", line 23 in run
524 File ".*threading.py", line [0-9]+ in _bootstrap_inner
525 File ".*threading.py", line [0-9]+ in _bootstrap
Victor Stinner024e37a2011-03-31 01:31:06 +0200526
Victor Stinner861d9ab2016-03-16 22:45:24 +0100527 Current thread 0x[0-9a-f]+ \(most recent call first\):
Victor Stinner6d201682014-08-10 19:50:08 +0200528 File "<string>", line {lineno} in dump
529 File "<string>", line 28 in <module>$
530 """
531 regex = dedent(regex.format(lineno=lineno)).strip()
Victor Stinner024e37a2011-03-31 01:31:06 +0200532 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200533 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200534
535 def test_dump_traceback_threads(self):
536 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200537
538 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200539 with temporary_filename() as filename:
540 self.check_dump_traceback_threads(filename)
541
Victor Stinner95bb7142015-03-12 15:32:03 +0100542 def check_dump_traceback_later(self, repeat=False, cancel=False, loops=1,
543 *, filename=None, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200544 """
545 Check how many times the traceback is written in timeout x 2.5 seconds,
546 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
547 on repeat and cancel options.
548
549 Raise an error if the output doesn't match the expect format.
550 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200551 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200552 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200553 import faulthandler
554 import time
Victor Stinner95bb7142015-03-12 15:32:03 +0100555 import sys
556
557 timeout = {timeout}
558 repeat = {repeat}
559 cancel = {cancel}
560 loops = {loops}
561 filename = {filename!r}
562 fd = {fd}
Victor Stinner024e37a2011-03-31 01:31:06 +0200563
Victor Stinner6d201682014-08-10 19:50:08 +0200564 def func(timeout, repeat, cancel, file, loops):
565 for loop in range(loops):
566 faulthandler.dump_traceback_later(timeout, repeat=repeat, file=file)
567 if cancel:
568 faulthandler.cancel_dump_traceback_later()
569 time.sleep(timeout * 5)
570 faulthandler.cancel_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200571
Victor Stinner95bb7142015-03-12 15:32:03 +0100572 if filename:
573 file = open(filename, "wb")
574 elif fd is not None:
575 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200576 else:
577 file = None
578 func(timeout, repeat, cancel, file, loops)
Victor Stinner95bb7142015-03-12 15:32:03 +0100579 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200580 file.close()
581 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200582 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200583 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200584 repeat=repeat,
585 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200586 loops=loops,
Victor Stinner95bb7142015-03-12 15:32:03 +0100587 filename=filename,
588 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200589 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200590 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200591 trace = '\n'.join(trace)
592
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200593 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200594 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200595 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200596 count *= 2
Guido van Rossum7be5d7d2013-10-20 18:21:02 -0700597 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+ \(most recent call first\):\n' % timeout_str
Victor Stinner95bb7142015-03-12 15:32:03 +0100598 regex = expected_traceback(17, 26, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200599 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200600 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200601 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200602 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200603
Georg Brandldeb92b52012-09-22 08:58:55 +0200604 def test_dump_traceback_later(self):
605 self.check_dump_traceback_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200606
Georg Brandldeb92b52012-09-22 08:58:55 +0200607 def test_dump_traceback_later_repeat(self):
608 self.check_dump_traceback_later(repeat=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200609
Georg Brandldeb92b52012-09-22 08:58:55 +0200610 def test_dump_traceback_later_cancel(self):
611 self.check_dump_traceback_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200612
Georg Brandldeb92b52012-09-22 08:58:55 +0200613 def test_dump_traceback_later_file(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100614 with temporary_filename() as filename:
615 self.check_dump_traceback_later(filename=filename)
616
Victor Stinnerff2a6612015-03-13 11:01:30 +0100617 @unittest.skipIf(sys.platform == "win32",
618 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100619 def test_dump_traceback_later_fd(self):
620 with tempfile.TemporaryFile('wb+') as fp:
621 self.check_dump_traceback_later(fd=fp.fileno())
Victor Stinner024e37a2011-03-31 01:31:06 +0200622
Georg Brandldeb92b52012-09-22 08:58:55 +0200623 def test_dump_traceback_later_twice(self):
Victor Stinner95bb7142015-03-12 15:32:03 +0100624 self.check_dump_traceback_later(loops=2)
Victor Stinnerde10f402011-04-08 12:57:06 +0200625
Victor Stinner024e37a2011-03-31 01:31:06 +0200626 @unittest.skipIf(not hasattr(faulthandler, "register"),
627 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200628 def check_register(self, filename=False, all_threads=False,
Victor Stinner95bb7142015-03-12 15:32:03 +0100629 unregister=False, chain=False, fd=None):
Victor Stinner024e37a2011-03-31 01:31:06 +0200630 """
631 Register a handler displaying the traceback on a user signal. Raise the
632 signal and check the written traceback.
633
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200634 If chain is True, check that the previous signal handler is called.
635
Victor Stinner024e37a2011-03-31 01:31:06 +0200636 Raise an error if the output doesn't match the expected format.
637 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200638 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200639 code = """
Victor Stinner6d201682014-08-10 19:50:08 +0200640 import faulthandler
641 import os
642 import signal
643 import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200644
Victor Stinner95bb7142015-03-12 15:32:03 +0100645 all_threads = {all_threads}
646 signum = {signum}
647 unregister = {unregister}
648 chain = {chain}
649 filename = {filename!r}
650 fd = {fd}
651
Victor Stinner6d201682014-08-10 19:50:08 +0200652 def func(signum):
653 os.kill(os.getpid(), signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200654
Victor Stinner6d201682014-08-10 19:50:08 +0200655 def handler(signum, frame):
656 handler.called = True
657 handler.called = False
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200658
Victor Stinner95bb7142015-03-12 15:32:03 +0100659 if filename:
660 file = open(filename, "wb")
661 elif fd is not None:
662 file = sys.stderr.fileno()
Victor Stinner6d201682014-08-10 19:50:08 +0200663 else:
664 file = None
665 if chain:
666 signal.signal(signum, handler)
667 faulthandler.register(signum, file=file,
Victor Stinner95bb7142015-03-12 15:32:03 +0100668 all_threads=all_threads, chain={chain})
Victor Stinner6d201682014-08-10 19:50:08 +0200669 if unregister:
670 faulthandler.unregister(signum)
671 func(signum)
672 if chain and not handler.called:
673 if file is not None:
674 output = file
675 else:
676 output = sys.stderr
677 print("Error: signal handler not called!", file=output)
678 exitcode = 1
Victor Stinner95bb7142015-03-12 15:32:03 +0100679 else:
680 exitcode = 0
681 if filename:
Victor Stinner6d201682014-08-10 19:50:08 +0200682 file.close()
683 sys.exit(exitcode)
684 """
Victor Stinner024e37a2011-03-31 01:31:06 +0200685 code = code.format(
Victor Stinner024e37a2011-03-31 01:31:06 +0200686 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200687 signum=signum,
688 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200689 chain=chain,
Victor Stinner95bb7142015-03-12 15:32:03 +0100690 filename=filename,
691 fd=fd,
Victor Stinner024e37a2011-03-31 01:31:06 +0200692 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200693 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200694 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200695 if not unregister:
696 if all_threads:
R David Murray44b548d2016-09-08 13:59:53 -0400697 regex = r'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
Victor Stinnera01ca122011-04-01 12:56:17 +0200698 else:
R David Murray44b548d2016-09-08 13:59:53 -0400699 regex = r'Stack \(most recent call first\):\n'
Victor Stinner95bb7142015-03-12 15:32:03 +0100700 regex = expected_traceback(14, 32, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200701 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200702 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200703 self.assertEqual(trace, '')
704 if unregister:
705 self.assertNotEqual(exitcode, 0)
706 else:
707 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200708
709 def test_register(self):
710 self.check_register()
711
Victor Stinnera01ca122011-04-01 12:56:17 +0200712 def test_unregister(self):
713 self.check_register(unregister=True)
714
Victor Stinner024e37a2011-03-31 01:31:06 +0200715 def test_register_file(self):
716 with temporary_filename() as filename:
717 self.check_register(filename=filename)
718
Victor Stinnerff2a6612015-03-13 11:01:30 +0100719 @unittest.skipIf(sys.platform == "win32",
720 "subprocess doesn't support pass_fds on Windows")
Victor Stinner95bb7142015-03-12 15:32:03 +0100721 def test_register_fd(self):
722 with tempfile.TemporaryFile('wb+') as fp:
723 self.check_register(fd=fp.fileno())
724
Victor Stinner024e37a2011-03-31 01:31:06 +0200725 def test_register_threads(self):
726 self.check_register(all_threads=True)
727
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200728 def test_register_chain(self):
729 self.check_register(chain=True)
730
Victor Stinnere2d66902014-05-14 17:15:50 +0200731 @contextmanager
732 def check_stderr_none(self):
733 stderr = sys.stderr
734 try:
735 sys.stderr = None
736 with self.assertRaises(RuntimeError) as cm:
737 yield
738 self.assertEqual(str(cm.exception), "sys.stderr is None")
739 finally:
740 sys.stderr = stderr
741
742 def test_stderr_None(self):
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300743 # Issue #21497: provide a helpful error if sys.stderr is None,
Victor Stinnere2d66902014-05-14 17:15:50 +0200744 # instead of just an attribute error: "None has no attribute fileno".
745 with self.check_stderr_none():
746 faulthandler.enable()
747 with self.check_stderr_none():
748 faulthandler.dump_traceback()
Victor Stinner0a963fb2019-09-18 14:15:10 +0200749 with self.check_stderr_none():
750 faulthandler.dump_traceback_later(1e-3)
Victor Stinnere2d66902014-05-14 17:15:50 +0200751 if hasattr(faulthandler, "register"):
752 with self.check_stderr_none():
753 faulthandler.register(signal.SIGUSR1)
754
Victor Stinner937ee9e2018-06-26 02:11:06 +0200755 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner404cdc52016-03-23 10:39:17 +0100756 def test_raise_exception(self):
757 for exc, name in (
758 ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
759 ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
760 ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
761 ):
Eric V. Smith451d0e32016-09-09 21:56:20 -0400762 self.check_windows_exception(f"""
Victor Stinner404cdc52016-03-23 10:39:17 +0100763 import faulthandler
764 faulthandler.enable()
765 faulthandler._raise_exception(faulthandler._{exc})
Eric V. Smith451d0e32016-09-09 21:56:20 -0400766 """,
Victor Stinner404cdc52016-03-23 10:39:17 +0100767 3,
768 name)
769
Victor Stinner937ee9e2018-06-26 02:11:06 +0200770 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner6e3d6b52017-10-09 09:52:32 -0700771 def test_ignore_exception(self):
772 for exc_code in (
773 0xE06D7363, # MSC exception ("Emsc")
774 0xE0434352, # COM Callable Runtime exception ("ECCR")
775 ):
776 code = f"""
777 import faulthandler
778 faulthandler.enable()
779 faulthandler._raise_exception({exc_code})
780 """
781 code = dedent(code)
782 output, exitcode = self.get_output(code)
783 self.assertEqual(output, [])
784 self.assertEqual(exitcode, exc_code)
785
Victor Stinner937ee9e2018-06-26 02:11:06 +0200786 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Steve Dowere6a23c82017-06-05 15:54:15 -0700787 def test_raise_nonfatal_exception(self):
788 # These exceptions are not strictly errors. Letting
789 # faulthandler display the traceback when they are
790 # raised is likely to result in noise. However, they
791 # may still terminate the process if there is no
792 # handler installed for them (which there typically
793 # is, e.g. for debug messages).
794 for exc in (
795 0x00000000,
796 0x34567890,
797 0x40000000,
798 0x40001000,
799 0x70000000,
800 0x7FFFFFFF,
801 ):
802 output, exitcode = self.get_output(f"""
803 import faulthandler
804 faulthandler.enable()
805 faulthandler._raise_exception(0x{exc:x})
806 """
807 )
808 self.assertEqual(output, [])
Victor Stinner6a1d84e2017-06-06 19:40:41 +0200809 # On Windows older than 7 SP1, the actual exception code has
810 # bit 29 cleared.
811 self.assertIn(exitcode,
812 (exc, exc & ~0x10000000))
Steve Dowere6a23c82017-06-05 15:54:15 -0700813
Victor Stinner937ee9e2018-06-26 02:11:06 +0200814 @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
Victor Stinner46c2b812017-04-21 18:06:13 +0200815 def test_disable_windows_exc_handler(self):
816 code = dedent("""
817 import faulthandler
818 faulthandler.enable()
819 faulthandler.disable()
820 code = faulthandler._EXCEPTION_ACCESS_VIOLATION
821 faulthandler._raise_exception(code)
822 """)
823 output, exitcode = self.get_output(code)
824 self.assertEqual(output, [])
825 self.assertEqual(exitcode, 0xC0000005)
Victor Stinner404cdc52016-03-23 10:39:17 +0100826
Thomas A Caswelle2783352019-08-29 12:30:04 -0400827 def test_cancel_later_without_dump_traceback_later(self):
828 # bpo-37933: Calling cancel_dump_traceback_later()
829 # without dump_traceback_later() must not segfault.
830 code = dedent("""
831 import faulthandler
832 faulthandler.cancel_dump_traceback_later()
833 """)
834 output, exitcode = self.get_output(code)
835 self.assertEqual(output, [])
836 self.assertEqual(exitcode, 0)
837
Victor Stinner024e37a2011-03-31 01:31:06 +0200838
Victor Stinner024e37a2011-03-31 01:31:06 +0200839if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400840 unittest.main()