Skip to content

Commit b8f96b5

Browse files
authored
gh-108253: Fix bug in func version cache (#108296)
When a function object changed its version, a stale pointer might remain in the cache. Zap these whenever `func_version` changes (even when set to 0).
1 parent adfc118 commit b8f96b5

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

Objects/funcobject.c

+22-22
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr)
131131
op->func_annotations = NULL;
132132
op->func_typeparams = NULL;
133133
op->vectorcall = _PyFunction_Vectorcall;
134-
op->func_version = 0;
134+
_PyFunction_SetVersion(op, 0);
135135
_PyObject_GC_TRACK(op);
136136
handle_func_event(PyFunction_EVENT_CREATE, op, NULL);
137137
return op;
@@ -207,7 +207,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
207207
op->func_annotations = NULL;
208208
op->func_typeparams = NULL;
209209
op->vectorcall = _PyFunction_Vectorcall;
210-
op->func_version = 0;
210+
_PyFunction_SetVersion(op, 0);
211211
_PyObject_GC_TRACK(op);
212212
handle_func_event(PyFunction_EVENT_CREATE, op, NULL);
213213
return (PyObject *)op;
@@ -268,9 +268,17 @@ code objects have been created during the process's lifetime.
268268
void
269269
_PyFunction_SetVersion(PyFunctionObject *func, uint32_t version)
270270
{
271+
PyInterpreterState *interp = _PyInterpreterState_GET();
272+
if (func->func_version != 0) {
273+
PyFunctionObject **slot =
274+
interp->func_state.func_version_cache
275+
+ (func->func_version % FUNC_VERSION_CACHE_SIZE);
276+
if (*slot == func) {
277+
*slot = NULL;
278+
}
279+
}
271280
func->func_version = version;
272281
if (version != 0) {
273-
PyInterpreterState *interp = _PyInterpreterState_GET();
274282
interp->func_state.func_version_cache[
275283
version % FUNC_VERSION_CACHE_SIZE] = func;
276284
}
@@ -370,7 +378,7 @@ PyFunction_SetDefaults(PyObject *op, PyObject *defaults)
370378
}
371379
handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS,
372380
(PyFunctionObject *) op, defaults);
373-
((PyFunctionObject *)op)->func_version = 0;
381+
_PyFunction_SetVersion((PyFunctionObject *)op, 0);
374382
Py_XSETREF(((PyFunctionObject *)op)->func_defaults, defaults);
375383
return 0;
376384
}
@@ -379,7 +387,7 @@ void
379387
PyFunction_SetVectorcall(PyFunctionObject *func, vectorcallfunc vectorcall)
380388
{
381389
assert(func != NULL);
382-
func->func_version = 0;
390+
_PyFunction_SetVersion(func, 0);
383391
func->vectorcall = vectorcall;
384392
}
385393

@@ -412,7 +420,7 @@ PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults)
412420
}
413421
handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS,
414422
(PyFunctionObject *) op, defaults);
415-
((PyFunctionObject *)op)->func_version = 0;
423+
_PyFunction_SetVersion((PyFunctionObject *)op, 0);
416424
Py_XSETREF(((PyFunctionObject *)op)->func_kwdefaults, defaults);
417425
return 0;
418426
}
@@ -445,7 +453,7 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure)
445453
Py_TYPE(closure)->tp_name);
446454
return -1;
447455
}
448-
((PyFunctionObject *)op)->func_version = 0;
456+
_PyFunction_SetVersion((PyFunctionObject *)op, 0);
449457
Py_XSETREF(((PyFunctionObject *)op)->func_closure, closure);
450458
return 0;
451459
}
@@ -507,7 +515,7 @@ PyFunction_SetAnnotations(PyObject *op, PyObject *annotations)
507515
"non-dict annotations");
508516
return -1;
509517
}
510-
((PyFunctionObject *)op)->func_version = 0;
518+
_PyFunction_SetVersion((PyFunctionObject *)op, 0);
511519
Py_XSETREF(((PyFunctionObject *)op)->func_annotations, annotations);
512520
return 0;
513521
}
@@ -566,7 +574,7 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
566574
return -1;
567575
}
568576
handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value);
569-
op->func_version = 0;
577+
_PyFunction_SetVersion(op, 0);
570578
Py_XSETREF(op->func_code, Py_NewRef(value));
571579
return 0;
572580
}
@@ -646,7 +654,7 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
646654
}
647655

648656
handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, op, value);
649-
op->func_version = 0;
657+
_PyFunction_SetVersion(op, 0);
650658
Py_XSETREF(op->func_defaults, Py_XNewRef(value));
651659
return 0;
652660
}
@@ -687,7 +695,7 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor
687695
}
688696

689697
handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, op, value);
690-
op->func_version = 0;
698+
_PyFunction_SetVersion(op, 0);
691699
Py_XSETREF(op->func_kwdefaults, Py_XNewRef(value));
692700
return 0;
693701
}
@@ -717,7 +725,7 @@ func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno
717725
"__annotations__ must be set to a dict object");
718726
return -1;
719727
}
720-
op->func_version = 0;
728+
_PyFunction_SetVersion(op, 0);
721729
Py_XSETREF(op->func_annotations, Py_XNewRef(value));
722730
return 0;
723731
}
@@ -881,7 +889,7 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
881889
static int
882890
func_clear(PyFunctionObject *op)
883891
{
884-
op->func_version = 0;
892+
_PyFunction_SetVersion(op, 0);
885893
Py_CLEAR(op->func_globals);
886894
Py_CLEAR(op->func_builtins);
887895
Py_CLEAR(op->func_module);
@@ -917,15 +925,7 @@ func_dealloc(PyFunctionObject *op)
917925
if (op->func_weakreflist != NULL) {
918926
PyObject_ClearWeakRefs((PyObject *) op);
919927
}
920-
if (op->func_version != 0) {
921-
PyInterpreterState *interp = _PyInterpreterState_GET();
922-
PyFunctionObject **slot =
923-
interp->func_state.func_version_cache
924-
+ (op->func_version % FUNC_VERSION_CACHE_SIZE);
925-
if (*slot == op) {
926-
*slot = NULL;
927-
}
928-
}
928+
_PyFunction_SetVersion(op, 0);
929929
(void)func_clear(op);
930930
// These aren't cleared by func_clear().
931931
Py_DECREF(op->func_code);

0 commit comments

Comments
 (0)