8000 Improve error messages for stack overflow · python/cpython@9c9326a · GitHub
[go: up one dir, main page]

Skip to content

Commit 9c9326a

Browse files
committed
Improve error messages for stack overflow
1 parent 857a7bb commit 9c9326a

File tree

3 files changed

+30
-46
lines changed

3 files changed

+30
-46
lines changed

Include/cpython/pystate.h

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct _ts {
113113
int py_recursion_limit;
114114

115115
// These are addresses, but we need to convert to ints to avoid UB.
116+
uintptr_t c_stack_top;
116117
uintptr_t c_stack_soft_limit;
117118
uintptr_t c_stack_hard_limit;
118119
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
@@ -204,48 +205,6 @@ struct _ts {
204205
PyObject *threading_local_sentinel;
205206
};
206207

207-
208-
#if defined(__s390x__)
209-
# define Py_C_STACK_SIZE 320000
210-
#elif defined(_WIN32) && defined(_M_ARM64)
211-
# define Py_C_STACK_SIZE 400000
212-
#elif defined(_WIN32)
213-
# define Py_C_STACK_SIZE 1200000
214-
#elif defined(__ANDROID__)
215-
// On an ARM64 emulator, API level 34 was OK with 10000, but API level 21
216-
// crashed in test_compiler_recursion_limit.
217-
# define Py_C_STACK_SIZE 1200000
218-
#elif defined(__sparc__)
219-
// test_descr crashed on sparc64 with >7000 but let's keep a margin of error.
220-
# define Py_C_STACK_SIZE 1600000
221-
#elif defined(__wasi__)
222-
// Based on wasmtime 16.
223-
# define Py_C_STACK_SIZE 2000000
224-
#elif defined(__hppa__) || defined(__powerpc64__)
225-
// test_descr crashed with >8000 but let's keep a margin of error.
226-
# define Py_C_STACK_SIZE 2000000
227-
#else
228-
// This value is duplicated in Lib/test/support/__init__.py
229-
# define Py_C_STACK_SIZE 5000000
230-
#endif
231-
232-
233-
#ifdef Py_DEBUG
234-
// A debug build is likely built with low optimization level which implies
235-
// higher stack memory usage than a release build: use a lower limit.
236-
# if defined(__has_feature) /* Clang */
237-
// Clang debug builds use a lot of stack space
238-
# define Py_C_RECURSION_LIMIT (Py_C_STACK_SIZE / 4000)
239-
# else
240-
# define Py_C_RECURSION_LIMIT (Py_C_STACK_SIZE / 2000)
241-
# endif
242-
#elif defined(_Py_ADDRESS_SANITIZER)
243-
# define Py_C_RECURSION_LIMIT (Py_C_STACK_SIZE / 600)
244-
#else
245-
# define Py_C_RECURSION_LIMIT (Py_C_STACK_SIZE / 300)
246-
#endif
247-
248-
249208
/* other API */
250209

251210
/* Similar to PyThreadState_Get(), but don't issue a fatal error
@@ -259,7 +218,6 @@ _PyThreadState_UncheckedGet(void)
259218
return PyThreadState_GetUnchecked();
260219
}
261220

262-
263221
// Disable tracing and profiling.
264222
PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate);
265223

Modules/_testcapimodule.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3213,7 +3213,6 @@ PyInit__testcapi(void)
32133213
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
32143214

32153215
PyModule_AddIntConstant(m, "the_number_three", 3);
3216-
PyModule_AddIntMacro(m, Py_C_RECURSION_LIMIT);
32173216
PyModule_AddObject(m, "INT32_MIN", PyLong_FromInt32(INT32_MIN));
32183217
PyModule_AddObject(m, "INT32_MAX", PyLong_FromInt32(INT32_MAX));
32193218
PyModule_AddObject(m, "UINT32_MAX", PyLong_FromUInt32(UINT32_MAX));

Python/ceval.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,33 @@ _Py_EnterRecursiveCallUnchecked(PyThreadState *tstate)
318318
}
319319
}
320320

321+
#if defined(__s390x__)
322+
# define Py_C_STACK_SIZE 320000
323+
#elif defined(_WIN32) && defined(_M_ARM64)
324+
# define Py_C_STACK_SIZE 400000
325+
#elif defined(_WIN32)
326+
# define Py_C_STACK_SIZE 1200000
327+
#elif defined(__ANDROID__)
328+
# define Py_C_STACK_SIZE 1200000
329+
#elif defined(__sparc__)
330+
// test_descr crashed on sparc64 with >7000 but let's keep a margin of error.
331+
# define Py_C_STACK_SIZE 1600000
332+
#elif defined(__wasi__)
333+
// Based on wasmtime 16.
334+
# define Py_C_STACK_SIZE 2000000
335+
#elif defined(__hppa__) || defined(__powerpc64__)
336+
// test_descr crashed with >8000 but let's keep a margin of error.
337+
# define Py_C_STACK_SIZE 2000000
338+
#else
339+
# define Py_C_STACK_SIZE 5000000
340+
#endif
341+
321342
void
322343
_Py_InitializeRecursionCheck(PyThreadState *tstate)
323344
{
324345
char here;
325346
uintptr_t here_addr = (uintptr_t)&here;
347+
tstate->c_stack_top = here_addr;
326348
#ifdef USE_STACKCHECK
327349
if (_PyOS_CheckStack(PYOS_STACK_MARGIN * 2) == 0) {
328350
tstate->c_stack_soft_limit = here_addr - PYOS_STACK_MARGIN_BYTES;
@@ -364,15 +386,20 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
364386
assert(tstate->c_stack_hard_limit != 0);
365387
if (here_addr < tstate->c_stack_hard_limit) {
366388
/* Overflowing while handling an overflow. Give up. */
367-
Py_FatalError("Cannot recover from stack overflow.");
389+
int kbytes_used = (tstate->c_stack_top - here_addr)/1024;
390+
char buffer[80];
391+
snprintf(buffer, 80, "Unrecoverable stack overflow (used %dkb)%s", kbytes_used, where);
392+
Py_FatalError(buffer);
368393
}
369394
if (tstate->recursion_headroom) {
370395
return 0;
371396
}
372397
else {
398+
int kbytes_used = (tstate->c_stack_top - here_addr)/1024;
373399
tstate->recursion_headroom++;
374400
_PyErr_Format(tstate, PyExc_RecursionError,
375-
"maximum recursion depth exceeded%s",
401+
"Stack overflow (used %dkb)S%s",
402+
kbytes_used,
376403
where);
377404
tstate->recursion_headroom--;
378405
return -1;

0 commit comments

Comments
 (0)
0