gh-132399: ensure correct alignment of PyInterpreterState (#132428)

This commit is contained in:
Bénédikt Tran
2025-04-19 11:03:06 +02:00
committed by GitHub
parent 8a9c6c4d16
commit 427e7fc099
2 changed files with 20 additions and 3 deletions

View File

@@ -754,6 +754,12 @@ struct _is {
* and should be placed at the beginning. */ * and should be placed at the beginning. */
struct _ceval_state ceval; struct _ceval_state ceval;
/* This structure is carefully allocated so that it's correctly aligned
* to avoid undefined behaviors during LOAD and STORE. The '_malloced'
* field stores the allocated pointer address that will later be freed.
*/
void *_malloced;
PyInterpreterState *next; PyInterpreterState *next;
int64_t id; int64_t id;

View File

@@ -569,11 +569,19 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
return _PyStatus_OK(); return _PyStatus_OK();
} }
static PyInterpreterState * static PyInterpreterState *
alloc_interpreter(void) alloc_interpreter(void)
{ {
return PyMem_RawCalloc(1, sizeof(PyInterpreterState)); size_t alignment = _Alignof(PyInterpreterState);
size_t allocsize = sizeof(PyInterpreterState) + alignment - 1;
void *mem = PyMem_RawCalloc(1, allocsize);
if (mem == NULL) {
return NULL;
}
PyInterpreterState *interp = _Py_ALIGN_UP(mem, alignment);
assert(_Py_IS_ALIGNED(interp, alignment));
interp->_malloced = mem;
return interp;
} }
static void static void
@@ -587,12 +595,15 @@ free_interpreter(PyInterpreterState *interp)
PyMem_RawFree(interp->obmalloc); PyMem_RawFree(interp->obmalloc);
interp->obmalloc = NULL; interp->obmalloc = NULL;
} }
PyMem_RawFree(interp); assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
PyMem_RawFree(interp->_malloced);
} }
} }
#ifndef NDEBUG #ifndef NDEBUG
static inline int check_interpreter_whence(long); static inline int check_interpreter_whence(long);
#endif #endif
/* Get the interpreter state to a minimal consistent state. /* Get the interpreter state to a minimal consistent state.
Further init happens in pylifecycle.c before it can be used. Further init happens in pylifecycle.c before it can be used.
All fields not initialized here are expected to be zeroed out, All fields not initialized here are expected to be zeroed out,