Issue #18408: Add a new PyFrame_FastToLocalsWithError() function to handle
exceptions when merging fast locals into f_locals of a frame.
PyEval_GetLocals() now raises an exception and return NULL on failure.
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 4713874..b0be671 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -755,8 +755,11 @@
     }
     if (globals == Py_None) {
         globals = PyEval_GetGlobals();
-        if (locals == Py_None)
+        if (locals == Py_None) {
             locals = PyEval_GetLocals();
+            if (locals == NULL)
+                return NULL;
+        }
     }
     else if (locals == Py_None)
         locals = globals;
@@ -820,6 +823,8 @@
         globals = PyEval_GetGlobals();
         if (locals == Py_None) {
             locals = PyEval_GetLocals();
+            if (locals == NULL)
+                return NULL;
         }
         if (!globals || !locals) {
             PyErr_SetString(PyExc_SystemError,
@@ -1926,13 +1931,9 @@
         return NULL;
     if (v == NULL) {
         d = PyEval_GetLocals();
-        if (d == NULL) {
-            if (!PyErr_Occurred())
-                PyErr_SetString(PyExc_SystemError,
-                                "vars(): no locals!?");
-        }
-        else
-            Py_INCREF(d);
+        if (d == NULL)
+            return NULL;
+        Py_INCREF(d);
     }
     else {
         _Py_IDENTIFIER(__dict__);
diff --git a/Python/ceval.c b/Python/ceval.c
index 2d52862..5f49615 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2472,7 +2472,9 @@
         TARGET(IMPORT_STAR) {
             PyObject *from = POP(), *locals;
             int err;
-            PyFrame_FastToLocals(f);
+            if (PyFrame_FastToLocalsWithError(f) < 0)
+                goto error;
+
             locals = f->f_locals;
             if (locals == NULL) {
                 PyErr_SetString(PyExc_SystemError,
@@ -4005,9 +4007,15 @@
 PyEval_GetLocals(void)
 {
     PyFrameObject *current_frame = PyEval_GetFrame();
-    if (current_frame == NULL)
+    if (current_frame == NULL) {
+        PyErr_SetString(PyExc_SystemError, "frame does not exist");
         return NULL;
-    PyFrame_FastToLocals(current_frame);
+    }
+
+    if (PyFrame_FastToLocalsWithError(current_frame) < 0)
+        return NULL;
+
+    assert(current_frame->f_locals != NULL);
     return current_frame->f_locals;
 }
 
@@ -4017,8 +4025,9 @@
     PyFrameObject *current_frame = PyEval_GetFrame();
     if (current_frame == NULL)
         return NULL;
-    else
-        return current_frame->f_globals;
+
+    assert(current_frame->f_globals != NULL);
+    return current_frame->f_globals;
 }
 
 PyFrameObject *
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index d8848ae..97ce059 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -332,12 +332,16 @@
 call_trampoline(PyThreadState *tstate, PyObject* callback,
                 PyFrameObject *frame, int what, PyObject *arg)
 {
-    PyObject *args = PyTuple_New(3);
+    PyObject *args;
     PyObject *whatstr;
     PyObject *result;
 
+    args = PyTuple_New(3);
     if (args == NULL)
         return NULL;
+    if (PyFrame_FastToLocalsWithError(frame) < 0)
+        return NULL;
+
     Py_INCREF(frame);
     whatstr = whatstrings[what];
     Py_INCREF(whatstr);
@@ -349,7 +353,6 @@
     PyTuple_SET_ITEM(args, 2, arg);
 
     /* call the Python-level function */
-    PyFrame_FastToLocals(frame);
     result = PyEval_CallObject(callback, args);
     PyFrame_LocalsToFast(frame, 1);
     if (result == NULL)