Skip to content

Commit

Permalink
bpo-42143: Ensure PyFunction_NewWithQualName() can't fail after creat…
Browse files Browse the repository at this point in the history
…ing the func object (pythonGH-22953)

func_dealloc() does not handle partially-created objects. Best not to give it any.
  • Loading branch information
Jongy committed Oct 29, 2020
1 parent df59273 commit 3505261
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix handling of errors during creation of ``PyFunctionObject``, which resulted
in operations on uninitialized memory. Patch by Yonatan Goldschmidt.
29 changes: 16 additions & 13 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,23 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
return NULL;
}

/* __module__: If module name is in globals, use it.
Otherwise, use None. */
module = PyDict_GetItemWithError(globals, __name__);
if (module) {
Py_INCREF(module);
}
else if (PyErr_Occurred()) {
return NULL;
}

op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL)
if (op == NULL) {
Py_XDECREF(module);
return NULL;
}
/* Note: No failures from this point on, since func_dealloc() does not
expect a partially-created object. */

op->func_weakreflist = NULL;
Py_INCREF(code);
Expand All @@ -34,6 +48,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
op->func_kwdefaults = NULL; /* No keyword only defaults */
op->func_closure = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_module = module;

consts = ((PyCodeObject *)code)->co_consts;
if (PyTuple_Size(consts) >= 1) {
Expand All @@ -47,20 +62,8 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
op->func_doc = doc;

op->func_dict = NULL;
op->func_module = NULL;
op->func_annotations = NULL;

/* __module__: If module name is in globals, use it.
Otherwise, use None. */
module = PyDict_GetItemWithError(globals, __name__);
if (module) {
Py_INCREF(module);
op->func_module = module;
}
else if (PyErr_Occurred()) {
Py_DECREF(op);
return NULL;
}
if (qualname)
op->func_qualname = qualname;
else
Expand Down

0 comments on commit 3505261

Please sign in to comment.