Skip to content

Commit 92d8672

Browse files
[3.14] gh-153531: fix thread safety of setting func.__doc__ and func.__module__ (GH-154851) (#154857)
gh-153531: fix thread safety of setting func.__doc__ and func.__module__ (GH-154851) (cherry picked from commit 9ccd5bb) Co-authored-by: Kumar Aditya <kumaraditya@python.org>
1 parent 9f071f0 commit 92d8672

2 files changed

Lines changed: 64 additions & 32 deletions

File tree

Lib/test/test_free_threading/test_functions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ def test_annotate(self):
5858
def test_type_params(self):
5959
self.stress_attribute("__type_params__", lambda: (random_string(),))
6060

61+
def test_doc(self):
62+
self.stress_attribute("__doc__", random_string)
63+
64+
def test_module(self):
65+
self.stress_attribute("__module__", random_string)
66+
6167
def test_annotations_and_annotate(self):
6268
# The __annotations__ and __annotate__ setters clear each other.
6369
def target(): pass

Objects/funcobject.c

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -644,9 +644,7 @@ PyFunction_SetAnnotations(PyObject *op, PyObject *annotations)
644644

645645
static PyMemberDef func_memberlist[] = {
646646
{"__closure__", _Py_T_OBJECT, OFF(func_closure), Py_READONLY},
647-
{"__doc__", _Py_T_OBJECT, OFF(func_doc), 0},
648647
{"__globals__", _Py_T_OBJECT, OFF(func_globals), Py_READONLY},
649-
{"__module__", _Py_T_OBJECT, OFF(func_module), 0},
650648
{"__builtins__", _Py_T_OBJECT, OFF(func_builtins), Py_READONLY},
651649
{NULL} /* Sentinel */
652650
};
@@ -777,6 +775,56 @@ func_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored))
777775
return 0;
778776
}
779777

778+
static PyObject *
779+
func_get_doc(PyObject *self, void *Py_UNUSED(ignored))
780+
{
781+
PyFunctionObject *op = _PyFunction_CAST(self);
782+
PyObject *doc = op->func_doc;
783+
if (doc == NULL) {
784+
doc = Py_None;
785+
}
786+
return Py_NewRef(doc);
787+
}
788+
789+
static int
790+
func_set_doc(PyObject *self, PyObject *value, void *Py_UNUSED(ignored))
791+
{
792+
/* Legal to del f.__doc__ or to set it to any object. */
793+
PyFunctionObject *op = _PyFunction_CAST(self);
794+
PyInterpreterState *interp = _PyInterpreterState_GET();
795+
_PyEval_StopTheWorld(interp);
796+
PyObject *old_doc = op->func_doc;
797+
op->func_doc = Py_XNewRef(value);
798+
_PyEval_StartTheWorld(interp);
799+
Py_XDECREF(old_doc);
800+
return 0;
801+
}
802+
803+
static PyObject *
804+
func_get_module(PyObject *self, void *Py_UNUSED(ignored))
805+
{
806+
PyFunctionObject *op = _PyFunction_CAST(self);
807+
PyObject *module = op->func_module;
808+
if (module == NULL) {
809+
module = Py_None;
810+
}
811+
return Py_NewRef(module);
812+
}
813+
814+
static int
815+
func_set_module(PyObject *self, PyObject *value, void *Py_UNUSED(ignored))
816+
{
817+
/* Legal to del f.__module__ or to set it to any object. */
818+
PyFunctionObject *op = _PyFunction_CAST(self);
819+
PyInterpreterState *interp = _PyInterpreterState_GET();
820+
_PyEval_StopTheWorld(interp);
821+
PyObject *old_module = op->func_module;
822+
op->func_module = Py_XNewRef(value);
823+
_PyEval_StartTheWorld(interp);
824+
Py_XDECREF(old_module);
825+
return 0;
826+
}
827+
780828
static PyObject *
781829
func_get_defaults(PyObject *self, void *Py_UNUSED(ignored))
782830
{
@@ -906,24 +954,12 @@ function___annotate___set_impl(PyFunctionObject *self, PyObject *value)
906954
return -1;
907955
}
908956
if (Py_IsNone(value)) {
909-
PyInterpreterState *interp = _PyInterpreterState_GET();
910-
_PyEval_StopTheWorld(interp);
911-
PyObject *old_annotate = self->func_annotate;
912-
self->func_annotate = Py_NewRef(value);
913-
_PyEval_StartTheWorld(interp);
914-
Py_XDECREF(old_annotate);
957+
Py_XSETREF(self->func_annotate, Py_NewRef(value));
915958
return 0;
916959
}
917960
else if (PyCallable_Check(value)) {
918-
PyInterpreterState *interp = _PyInterpreterState_GET();
919-
_PyEval_StopTheWorld(interp);
920-
PyObject *old_annotate = self->func_annotate;
921-
self->func_annotate = Py_NewRef(value);
922-
PyObject *old_annotations = self->func_annotations;
923-
self->func_annotations = NULL;
924-
_PyEval_StartTheWorld(interp);
925-
Py_XDECREF(old_annotate);
926-
Py_XDECREF(old_annotations);
961+
Py_XSETREF(self->func_annotate, Py_NewRef(value));
962+
Py_CLEAR(self->func_annotations);
927963
return 0;
928964
}
929965
else {
@@ -976,15 +1012,8 @@ function___annotations___set_impl(PyFunctionObject *self, PyObject *value)
9761012
"__annotations__ must be set to a dict object");
9771013
return -1;
9781014
}
979-
PyInterpreterState *interp = _PyInterpreterState_GET();
980-
_PyEval_StopTheWorld(interp);
981-
PyObject *old_annotations = self->func_annotations;
982-
self->func_annotations = Py_XNewRef(value);
983-
PyObject *old_annotate = self->func_annotate;
984-
self->func_annotate = NULL;
985-
_PyEval_StartTheWorld(interp);
986-
Py_XDECREF(old_annotations);
987-
Py_XDECREF(old_annotate);
1015+
Py_XSETREF(self->func_annotations, Py_XNewRef(value));
1016+
Py_CLEAR(self->func_annotate);
9881017
return 0;
9891018
}
9901019

@@ -1025,12 +1054,7 @@ function___type_params___set_impl(PyFunctionObject *self, PyObject *value)
10251054
"__type_params__ must be set to a tuple");
10261055
return -1;
10271056
}
1028-
PyInterpreterState *interp = _PyInterpreterState_GET();
1029-
_PyEval_StopTheWorld(interp);
1030-
PyObject *old_typeparams = self->func_typeparams;
1031-
self->func_typeparams = Py_NewRef(value);
1032-
_PyEval_StartTheWorld(interp);
1033-
Py_XDECREF(old_typeparams);
1057+
Py_XSETREF(self->func_typeparams, Py_NewRef(value));
10341058
return 0;
10351059
}
10361060

@@ -1052,6 +1076,8 @@ static PyGetSetDef func_getsetlist[] = {
10521076
FUNCTION___ANNOTATIONS___GETSETDEF
10531077
FUNCTION___ANNOTATE___GETSETDEF
10541078
{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1079+
{"__doc__", func_get_doc, func_set_doc},
1080+
{"__module__", func_get_module, func_set_module},
10551081
{"__name__", func_get_name, func_set_name},
10561082
{"__qualname__", func_get_qualname, func_set_qualname},
10571083
FUNCTION___TYPE_PARAMS___GETSETDEF

0 commit comments

Comments
 (0)