]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132399: ensure correct alignment of `PyInterpreterState` (#132428)
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Sat, 19 Apr 2025 09:03:06 +0000 (11:03 +0200)
committerGitHub <noreply@github.com>
Sat, 19 Apr 2025 09:03:06 +0000 (11:03 +0200)
Include/internal/pycore_interp_structs.h
Python/pystate.c

index 573b56a57e1d542e1165ce444ebc2dfa271ca078..9ac4b4630abd3fc95e5615b1beb57ae90da3f474 100644 (file)
@@ -754,6 +754,12 @@ struct _is {
      * and should be placed at the beginning. */
     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;
 
     int64_t id;
index ee35f0fa945f8b9bb29865f9b05a2949e656b366..aba558279a657d8f406ad990d8312fc7abd13728 100644 (file)
@@ -569,11 +569,19 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
     return _PyStatus_OK();
 }
 
-
 static PyInterpreterState *
 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
@@ -587,12 +595,15 @@ free_interpreter(PyInterpreterState *interp)
             PyMem_RawFree(interp->obmalloc);
             interp->obmalloc = NULL;
         }
-        PyMem_RawFree(interp);
+        assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
+        PyMem_RawFree(interp->_malloced);
     }
 }
+
 #ifndef NDEBUG
 static inline int check_interpreter_whence(long);
 #endif
+
 /* Get the interpreter state to a minimal consistent state.
    Further init happens in pylifecycle.c before it can be used.
    All fields not initialized here are expected to be zeroed out,