Commit 652e7076 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #5392: when a very low recursion limit was set, the interpreter would

abort with a fatal error after the recursion limit was hit twice.
parent ae2dbe25
...@@ -92,11 +92,10 @@ PyAPI_DATA(int) _Py_CheckRecursionLimit; ...@@ -92,11 +92,10 @@ PyAPI_DATA(int) _Py_CheckRecursionLimit;
# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) # define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit)
#endif #endif
#ifdef USE_STACKCHECK #define _Py_MakeEndRecCheck(x) \
# define _Py_MakeEndRecCheck(x) (--(x) < _Py_CheckRecursionLimit - 50) (--(x) < ((_Py_CheckRecursionLimit > 100) \
#else ? (_Py_CheckRecursionLimit - 50) \
# define _Py_MakeEndRecCheck(x) (--(x) < _Py_CheckRecursionLimit - 50) : (3 * (_Py_CheckRecursionLimit >> 2))))
#endif
#define Py_ALLOW_RECURSION \ #define Py_ALLOW_RECURSION \
do { unsigned char _old = PyThreadState_GET()->recursion_critical;\ do { unsigned char _old = PyThreadState_GET()->recursion_critical;\
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
import unittest, test.support import unittest, test.support
import sys, io, os import sys, io, os
import struct import struct
import subprocess
import textwrap
class SysModuleTest(unittest.TestCase): class SysModuleTest(unittest.TestCase):
...@@ -155,6 +157,46 @@ class SysModuleTest(unittest.TestCase): ...@@ -155,6 +157,46 @@ class SysModuleTest(unittest.TestCase):
self.assertEqual(sys.getrecursionlimit(), 10000) self.assertEqual(sys.getrecursionlimit(), 10000)
sys.setrecursionlimit(oldlimit) sys.setrecursionlimit(oldlimit)
def test_recursionlimit_recovery(self):
# NOTE: this test is slightly fragile in that it depends on the current
# recursion count when executing the test being low enough so as to
# trigger the recursion recovery detection in the _Py_MakeEndRecCheck
# macro (see ceval.h).
oldlimit = sys.getrecursionlimit()
def f():
f()
try:
for i in (50, 1000):
# Issue #5392: stack overflow after hitting recursion limit twice
sys.setrecursionlimit(i)
self.assertRaises(RuntimeError, f)
self.assertRaises(RuntimeError, f)
finally:
sys.setrecursionlimit(oldlimit)
def test_recursionlimit_fatalerror(self):
# A fatal error occurs if a second recursion limit is hit when recovering
# from a first one.
code = textwrap.dedent("""
import sys
def f():
try:
f()
except RuntimeError:
f()
sys.setrecursionlimit(%d)
f()""")
for i in (50, 1000):
sub = subprocess.Popen([sys.executable, '-c', code % i],
stderr=subprocess.PIPE)
err = sub.communicate()[1]
self.assertTrue(sub.returncode, sub.returncode)
self.assertTrue(
b"Fatal Python error: Cannot recover from stack overflow" in err,
err)
def test_getwindowsversion(self): def test_getwindowsversion(self):
if hasattr(sys, "getwindowsversion"): if hasattr(sys, "getwindowsversion"):
v = sys.getwindowsversion() v = sys.getwindowsversion()
......
...@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 2? ...@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 2?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #5392: when a very low recursion limit was set, the interpreter would
abort with a fatal error after the recursion limit was hit twice.
Library Library
------- -------
...@@ -24,8 +27,6 @@ What's New in Python 3.1 alpha 1 ...@@ -24,8 +27,6 @@ What's New in Python 3.1 alpha 1
Core and Builtins Core and Builtins
----------------- -----------------
=======
- The io module has been reimplemented in C for speed. - The io module has been reimplemented in C for speed.
- Give dict views an informative __repr__. - Give dict views an informative __repr__.
......
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