bpo-46090: Allow PyThreadState.datastack_* members to be NULL (GH-30234)

This commit is contained in:
Brandt Bucher 2021-12-28 09:49:48 -08:00 committed by GitHub
parent 02b5417f11
commit 77195cd44b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 25 deletions

View file

@ -174,11 +174,14 @@ static inline InterpreterFrame *
_PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size) _PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size)
{ {
PyObject **base = tstate->datastack_top; PyObject **base = tstate->datastack_top;
if (base) {
PyObject **top = base + size; PyObject **top = base + size;
assert(tstate->datastack_limit);
if (top < tstate->datastack_limit) { if (top < tstate->datastack_limit) {
tstate->datastack_top = top; tstate->datastack_top = top;
return (InterpreterFrame *)base; return (InterpreterFrame *)base;
} }
}
return _PyThreadState_BumpFramePointerSlow(tstate, size); return _PyThreadState_BumpFramePointerSlow(tstate, size);
} }

View file

@ -749,8 +749,7 @@ free_threadstate(PyThreadState *tstate)
static void static void
init_threadstate(PyThreadState *tstate, init_threadstate(PyThreadState *tstate,
PyInterpreterState *interp, uint64_t id, PyInterpreterState *interp, uint64_t id,
PyThreadState *next, PyThreadState *next)
_PyStackChunk *datastack_chunk)
{ {
if (tstate->_initialized) { if (tstate->_initialized) {
Py_FatalError("thread state already initialized"); Py_FatalError("thread state already initialized");
@ -784,11 +783,9 @@ init_threadstate(PyThreadState *tstate,
tstate->exc_info = &tstate->exc_state; tstate->exc_info = &tstate->exc_state;
tstate->cframe = &tstate->root_cframe; tstate->cframe = &tstate->root_cframe;
assert(datastack_chunk != NULL); tstate->datastack_chunk = NULL;
tstate->datastack_chunk = datastack_chunk; tstate->datastack_top = NULL;
/* If top points to entry 0, then _PyThreadState_PopFrame will try to pop this chunk */ tstate->datastack_limit = NULL;
tstate->datastack_top = &tstate->datastack_chunk->data[1];
tstate->datastack_limit = (PyObject **)(((char *)tstate->datastack_chunk) + DATA_STACK_CHUNK_SIZE);
tstate->_initialized = 1; tstate->_initialized = 1;
} }
@ -799,11 +796,6 @@ new_threadstate(PyInterpreterState *interp)
PyThreadState *tstate; PyThreadState *tstate;
_PyRuntimeState *runtime = interp->runtime; _PyRuntimeState *runtime = interp->runtime;
_PyStackChunk *datastack_chunk = allocate_chunk(DATA_STACK_CHUNK_SIZE, NULL);
if (datastack_chunk == NULL) {
return NULL;
}
/* We serialize concurrent creation to protect global state. */ /* We serialize concurrent creation to protect global state. */
HEAD_LOCK(runtime); HEAD_LOCK(runtime);
@ -833,14 +825,13 @@ new_threadstate(PyInterpreterState *interp)
} }
interp->threads.head = tstate; interp->threads.head = tstate;
init_threadstate(tstate, interp, id, old_head, datastack_chunk); init_threadstate(tstate, interp, id, old_head);
HEAD_UNLOCK(runtime); HEAD_UNLOCK(runtime);
return tstate; return tstate;
error: error:
HEAD_UNLOCK(runtime); HEAD_UNLOCK(runtime);
_PyObject_VirtualFree(datastack_chunk, datastack_chunk->size);
return NULL; return NULL;
} }
@ -2186,8 +2177,6 @@ _Py_GetConfig(void)
static PyObject ** static PyObject **
push_chunk(PyThreadState *tstate, int size) push_chunk(PyThreadState *tstate, int size)
{ {
assert(tstate->datastack_top + size >= tstate->datastack_limit);
int allocate_size = DATA_STACK_CHUNK_SIZE; int allocate_size = DATA_STACK_CHUNK_SIZE;
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) { while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
allocate_size *= 2; allocate_size *= 2;
@ -2196,10 +2185,16 @@ push_chunk(PyThreadState *tstate, int size)
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;
} }
tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0]; if (tstate->datastack_chunk) {
tstate->datastack_chunk->top = tstate->datastack_top -
&tstate->datastack_chunk->data[0];
}
tstate->datastack_chunk = new; tstate->datastack_chunk = new;
tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size); tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size);
PyObject **res = &new->data[0]; // When new is the "root" chunk (i.e. new->previous == NULL), we can keep
// _PyThreadState_PopFrame from freeing it later by "skipping" over the
// first element:
PyObject **res = &new->data[new->previous == NULL];
tstate->datastack_top = res + size; tstate->datastack_top = res + size;
return res; return res;
} }
@ -2212,9 +2207,6 @@ _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
PyObject **top = base + size; PyObject **top = base + size;
if (top >= tstate->datastack_limit) { if (top >= tstate->datastack_limit) {
base = push_chunk(tstate, (int)size); base = push_chunk(tstate, (int)size);
if (base == NULL) {
return NULL;
}
} }
else { else {
tstate->datastack_top = top; tstate->datastack_top = top;
@ -2244,16 +2236,20 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject
void void
_PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame)
{ {
assert(tstate->datastack_chunk);
PyObject **base = (PyObject **)frame; PyObject **base = (PyObject **)frame;
if (base == &tstate->datastack_chunk->data[0]) { if (base == &tstate->datastack_chunk->data[0]) {
_PyStackChunk *chunk = tstate->datastack_chunk; _PyStackChunk *chunk = tstate->datastack_chunk;
_PyStackChunk *previous = chunk->previous; _PyStackChunk *previous = chunk->previous;
// push_chunk ensures that the root chunk is never popped:
assert(previous);
tstate->datastack_top = &previous->data[previous->top]; tstate->datastack_top = &previous->data[previous->top];
tstate->datastack_chunk = previous; tstate->datastack_chunk = previous;
_PyObject_VirtualFree(chunk, chunk->size); _PyObject_VirtualFree(chunk, chunk->size);
tstate->datastack_limit = (PyObject **)(((char *)previous) + previous->size); tstate->datastack_limit = (PyObject **)(((char *)previous) + previous->size);
} }
else { else {
assert(tstate->datastack_top);
assert(tstate->datastack_top >= base); assert(tstate->datastack_top >= base);
tstate->datastack_top = base; tstate->datastack_top = base;
} }