Commit 27708dc9 authored by Victor Stinner's avatar Victor Stinner

Issue #11393: limit stack overflow test to 100 MB

Stop if the stack overflow doesn't occur after allocating 100 MB on the stack.
parent 8c419b79
...@@ -69,7 +69,7 @@ class FaultHandlerTests(unittest.TestCase): ...@@ -69,7 +69,7 @@ class FaultHandlerTests(unittest.TestCase):
return output.splitlines() return output.splitlines()
def check_fatal_error(self, code, line_number, name_regex, def check_fatal_error(self, code, line_number, name_regex,
filename=None, all_threads=False): filename=None, all_threads=False, other_regex=None):
""" """
Check that the fault handler for fatal errors is enabled and check the Check that the fault handler for fatal errors is enabled and check the
traceback from the child process output. traceback from the child process output.
...@@ -90,6 +90,8 @@ class FaultHandlerTests(unittest.TestCase): ...@@ -90,6 +90,8 @@ class FaultHandlerTests(unittest.TestCase):
lineno=line_number, lineno=line_number,
name=name_regex, name=name_regex,
header=re.escape(header)) header=re.escape(header))
if other_regex:
regex += '|' + other_regex
output = self.get_output(code, False, filename) output = self.get_output(code, False, filename)
output = '\n'.join(output) output = '\n'.join(output)
self.assertRegex(output, regex) self.assertRegex(output, regex)
...@@ -153,7 +155,6 @@ faulthandler._fatal_error(b'xyz') ...@@ -153,7 +155,6 @@ faulthandler._fatal_error(b'xyz')
2, 2,
'xyz') 'xyz')
@unittest.skipIf(True, 'test disabled, see #11393')
@unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'), @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
'need faulthandler._stack_overflow()') 'need faulthandler._stack_overflow()')
def test_stack_overflow(self): def test_stack_overflow(self):
...@@ -163,7 +164,8 @@ faulthandler.enable() ...@@ -163,7 +164,8 @@ faulthandler.enable()
faulthandler._stack_overflow() faulthandler._stack_overflow()
""".strip(), """.strip(),
3, 3,
'(?:Segmentation fault|Bus error)') '(?:Segmentation fault|Bus error)',
other_regex='unable to raise a stack overflow')
def test_gil_released(self): def test_gil_released(self):
self.check_fatal_error(""" self.check_fatal_error("""
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
# define FAULTHANDLER_USER # define FAULTHANDLER_USER
#endif #endif
/* Allocate at maximum 100 MB of the stack to raise the stack overflow */
#define STACK_OVERFLOW_MAX_SIZE (100*1024*1024)
#define PUTS(fd, str) write(fd, str, strlen(str)) #define PUTS(fd, str) write(fd, str, strlen(str))
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
...@@ -742,15 +745,39 @@ faulthandler_fatal_error_py(PyObject *self, PyObject *args) ...@@ -742,15 +745,39 @@ faulthandler_fatal_error_py(PyObject *self, PyObject *args)
} }
#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
static PyObject * void*
faulthandler_stack_overflow(PyObject *self) stack_overflow(void *min_sp, void *max_sp, size_t *depth)
{ {
/* allocate 4096 bytes on the stack at each call */ /* allocate 4096 bytes on the stack at each call */
unsigned char buffer[4096]; unsigned char buffer[4096];
void *sp = &buffer;
*depth += 1;
if (sp < min_sp || max_sp < sp)
return sp;
buffer[0] = 1; buffer[0] = 1;
buffer[4095] = 2; buffer[4095] = 0;
faulthandler_stack_overflow(self); return stack_overflow(min_sp, max_sp, depth);
return PyLong_FromLong(buffer[0] + buffer[4095]); }
static PyObject *
faulthandler_stack_overflow(PyObject *self)
{
size_t depth, size;
void *sp = &depth, *stop;
depth = 0;
stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
sp + STACK_OVERFLOW_MAX_SIZE,
&depth);
if (sp < stop)
size = stop - sp;
else
size = sp - stop;
PyErr_Format(PyExc_RuntimeError,
"unable to raise a stack overflow (allocated %zu bytes "
"on the stack, %zu recursive calls)",
size, depth);
return NULL;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment