Skip to content

Commit 9b08f8c

Browse files
authored
GH-126910: Revert "Make _Py_get_machine_stack_pointer return the stack pointer (#147945)" (GH-147994)
Revert "GH-126910: Make `_Py_get_machine_stack_pointer` return the stack pointer (#147945)" This reverts commit 255026d, which broke a tier-1 buildbot.
1 parent fc7a188 commit 9b08f8c

File tree

7 files changed

+55
-37
lines changed

7 files changed

+55
-37
lines changed

Include/internal/pycore_ceval.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,16 @@ extern void _PyEval_DeactivateOpCache(void);
211211

212212
/* --- _Py_EnterRecursiveCall() ----------------------------------------- */
213213

214-
static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) {
214+
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
215215
uintptr_t here_addr = _Py_get_machine_stack_pointer();
216216
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
217-
// Possible overflow if stack pointer is beyond the soft limit.
218-
// _Py_CheckRecursiveCall will check for corner cases and
219-
// report an error if there is an overflow.
217+
// Overflow if stack pointer is between soft limit and the base of the hardware stack.
218+
// If it is below the hardware stack base, assume that we have the wrong stack limits, and do nothing.
219+
// We could have the wrong stack limits because of limited platform support, or user-space threads.
220220
#if _Py_STACK_GROWS_DOWN
221-
return here_addr < _tstate->c_stack_soft_limit;
221+
return here_addr < _tstate->c_stack_soft_limit && here_addr >= _tstate->c_stack_soft_limit - 2 * _PyOS_STACK_MARGIN_BYTES;
222222
#else
223-
return here_addr > _tstate->c_stack_soft_limit;
223+
return here_addr > _tstate->c_stack_soft_limit && here_addr <= _tstate->c_stack_soft_limit + 2 * _PyOS_STACK_MARGIN_BYTES;
224224
#endif
225225
}
226226

@@ -235,7 +235,7 @@ PyAPI_FUNC(int) _Py_CheckRecursiveCallPy(
235235

236236
static inline int _Py_EnterRecursiveCallTstate(PyThreadState *tstate,
237237
const char *where) {
238-
return (_Py_ReachedRecursionLimit(tstate) && _Py_CheckRecursiveCall(tstate, where));
238+
return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
239239
}
240240

241241
static inline int _Py_EnterRecursiveCall(const char *where) {
@@ -249,6 +249,8 @@ static inline void _Py_LeaveRecursiveCallTstate(PyThreadState *tstate) {
249249

250250
PyAPI_FUNC(void) _Py_InitializeRecursionLimits(PyThreadState *tstate);
251251

252+
PyAPI_FUNC(int) _Py_ReachedRecursionLimit(PyThreadState *tstate);
253+
252254
// Export for test_peg_generator
253255
PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(
254256
PyThreadState *tstate,

Include/internal/pycore_pystate.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -306,23 +306,23 @@ _Py_AssertHoldsTstateFunc(const char *func)
306306
#define _Py_AssertHoldsTstate()
307307
#endif
308308

309+
#if !_Py__has_builtin(__builtin_frame_address) && !defined(__GNUC__) && !defined(_MSC_VER)
310+
static uintptr_t return_pointer_as_int(char* p) {
311+
return (uintptr_t)p;
312+
}
313+
#endif
309314

310315
static inline uintptr_t
311316
_Py_get_machine_stack_pointer(void) {
312-
uintptr_t result;
313-
#if !defined(_MSC_VER) && defined(_M_ARM64)
314-
result = __getReg(31);
315-
#elif defined(_MSC_VER) && defined(_M_X64)
316-
result = (uintptr_t)_AddressOfReturnAddress();
317-
#elif defined(__aarch64__)
318-
__asm__ ("mov %0, sp" : "=r" (result));
319-
#elif defined(__x86_64__)
320-
__asm__("{movq %%rsp, %0" : "=r" (result));
317+
#if _Py__has_builtin(__builtin_frame_address) || defined(__GNUC__)
318+
return (uintptr_t)__builtin_frame_address(0);
319+
#elif defined(_MSC_VER)
320+
return (uintptr_t)_AddressOfReturnAddress();
321321
#else
322322
char here;
323-
result = (uintptr_t)&here;
323+
/* Avoid compiler warning about returning stack address */
324+
return return_pointer_as_int(&here);
324325
#endif
325-
return result;
326326
}
327327

328328
static inline intptr_t

Include/internal/pycore_pythonrun.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ extern PyObject * _Py_CompileStringObjectWithModule(
4646
* stack consumption of PyEval_EvalDefault */
4747
#if (defined(Py_DEBUG) \
4848
|| defined(_Py_ADDRESS_SANITIZER) \
49-
|| defined(_Py_THREAD_SANITIZER)) \
50-
|| defined(_Py_UNDEFINED_BEHAVIOR_SANITIZER)
49+
|| defined(_Py_THREAD_SANITIZER))
5150
# define _PyOS_LOG2_STACK_MARGIN 12
5251
#else
5352
# define _PyOS_LOG2_STACK_MARGIN 11

Include/pyport.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -598,11 +598,6 @@ extern "C" {
598598
# define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
599599
# endif
600600
# endif
601-
# if __has_feature(undefined_behavior_sanitizer)
602-
# if !defined(_Py_UNDEFINED_BEHAVIOR_SANITIZER)
603-
# define _Py_UNDEFINED_BEHAVIOR_SANITIZER
604-
# endif
605-
# endif
606601
#elif defined(__GNUC__)
607602
# if defined(__SANITIZE_ADDRESS__)
608603
# define _Py_ADDRESS_SANITIZER

Lib/test/test_pyexpat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ def test_trigger_leak(self):
707707
def test_deeply_nested_content_model(self):
708708
# This should raise a RecursionError and not crash.
709709
# See https://github.com/python/cpython/issues/145986.
710-
N = 800_000
710+
N = 500_000
711711
data = (
712712
b'<!DOCTYPE root [\n<!ELEMENT root '
713713
+ b'(a, ' * N + b'a' + b')' * N

Python/ceval.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count)
4949
#endif
5050
}
5151

52+
void
53+
_Py_EnterRecursiveCallUnchecked(PyThreadState *tstate)
54+
{
55+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
56+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
57+
#if _Py_STACK_GROWS_DOWN
58+
if (here_addr < _tstate->c_stack_hard_limit) {
59+
#else
60+
if (here_addr > _tstate->c_stack_hard_limit) {
61+
#endif
62+
Py_FatalError("Unchecked stack overflow.");
63+
}
64+
}
65+
5266
#if defined(__s390x__)
5367
# define Py_C_STACK_SIZE 320000
5468
#elif defined(_WIN32)
@@ -264,7 +278,7 @@ PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)
264278

265279

266280
/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
267-
if the stack pointer is beyond c_stack_soft_limit. */
281+
if the stack pointer is between the stack base and c_stack_hard_limit. */
268282
int
269283
_Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
270284
{
@@ -273,21 +287,16 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
273287
assert(_tstate->c_stack_soft_limit != 0);
274288
assert(_tstate->c_stack_hard_limit != 0);
275289
#if _Py_STACK_GROWS_DOWN
290+
assert(here_addr >= _tstate->c_stack_hard_limit - _PyOS_STACK_MARGIN_BYTES);
276291
if (here_addr < _tstate->c_stack_hard_limit) {
277-
if (here_addr < _tstate->c_stack_hard_limit - _PyOS_STACK_MARGIN_BYTES) {
278-
// Far out of bounds -- Assume stack switching has occurred
279-
return 0;
280-
}
292+
/* Overflowing while handling an overflow. Give up. */
281293
int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024;
282294
#else
295+
assert(here_addr <= _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES);
283296
if (here_addr > _tstate->c_stack_hard_limit) {
284-
if (here_addr > _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES) {
285-
// Far out of bounds -- Assume stack switching has occurred
286-
return 0;
287-
}
297+
/* Overflowing while handling an overflow. Give up. */
288298
int kbytes_used = (int)(here_addr - _tstate->c_stack_top)/1024;
289299
#endif
290-
/* Too much stack used to safely raise an exception. Give up. */
291300
char buffer[80];
292301
snprintf(buffer, 80, "Unrecoverable stack overflow (used %d kB)%s", kbytes_used, where);
293302
Py_FatalError(buffer);
@@ -1192,6 +1201,19 @@ _PyEval_GetIter(_PyStackRef iterable, _PyStackRef *index_or_null, int yield_from
11921201
return PyStackRef_FromPyObjectSteal(iter_o);
11931202
}
11941203

1204+
Py_NO_INLINE int
1205+
_Py_ReachedRecursionLimit(PyThreadState *tstate) {
1206+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
1207+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
1208+
assert(_tstate->c_stack_hard_limit != 0);
1209+
#if _Py_STACK_GROWS_DOWN
1210+
return here_addr <= _tstate->c_stack_soft_limit;
1211+
#else
1212+
return here_addr >= _tstate->c_stack_soft_limit;
1213+
#endif
1214+
}
1215+
1216+
11951217
#if (defined(__GNUC__) && __GNUC__ >= 10 && !defined(__clang__)) && defined(__x86_64__)
11961218
/*
11971219
* gh-129987: The SLP autovectorizer can cause poor code generation for

Python/jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
734734
return 0;
735735
}
736736

737-
/* One-off compilation of the jit entry shim.
737+
/* One-off compilation of the jit entry shim
738738
* We compile this once only as it effectively a normal
739739
* function, but we need to use the JIT because it needs
740740
* to understand the jit-specific calling convention.

0 commit comments

Comments
 (0)