diff --git a/Include/object.h b/Include/object.h index 13e88a6dc6f02a..2e9442484c496d 100644 --- a/Include/object.h +++ b/Include/object.h @@ -218,6 +218,7 @@ PyAPI_FUNC(PyObject *) PyType_GenericAlloc(struct _typeobject *, Py_ssize_t); PyAPI_FUNC(PyObject *) PyType_GenericNew(struct _typeobject *, PyObject *, PyObject *); PyAPI_FUNC(unsigned int) PyType_ClearCache(void); +PyAPI_FUNC(void) PyType_InvalidateCache(PyObject *, PyObject *); PyAPI_FUNC(void) PyType_Modified(struct _typeobject *); /* Generic operations on objects */ diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-06-18-16-42.bpo-28866.4ibrlG.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-06-18-16-42.bpo-28866.4ibrlG.rst new file mode 100644 index 00000000000000..71d9909a76236b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-06-18-16-42.bpo-28866.4ibrlG.rst @@ -0,0 +1,2 @@ +Invalidating method cache of PyType even when the tp_setattro does not use +PyType one, to avoid a segfault. diff --git a/Objects/object.c b/Objects/object.c index 589bf365e870fd..3e2b16cd6363e1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1038,6 +1038,8 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) PyUnicode_InternInPlace(&name); if (tp->tp_setattro != NULL) { + if (PyType_CheckExact(v)) + PyType_InvalidateCache(v, name); err = (*tp->tp_setattro)(v, name, value); Py_DECREF(name); return err; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 37df4d23e4c192..a8c5a65d519b69 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -228,6 +228,25 @@ PyType_ClearCache(void) return cur_version_tag; } +void +PyType_InvalidateCache(PyObject *type, PyObject *name) +{ + unsigned int h; + PyTypeObject *t; + + t = (PyTypeObject *)type; + if (MCACHE_CACHEABLE_NAME(name) && + PyType_HasFeature(t, Py_TPFLAGS_VALID_VERSION_TAG)) { + h = MCACHE_HASH_METHOD(t, name); + method_cache[h].version = 0; + if (method_cache[h].name != Py_None) { + Py_INCREF(Py_None); + Py_XSETREF(method_cache[h].name, Py_None); + } + method_cache[h].value = NULL; + } +} + void _PyType_Fini(void) {