From 6098526133deaa4c43a45a4ce4165ff72aeb8906 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 6 May 2019 15:59:08 +0200 Subject: [PATCH 1/4] Invalidate type cache on setattr. --- Include/object.h | 1 + Objects/object.c | 1 + Objects/typeobject.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+) 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/Objects/object.c b/Objects/object.c index 589bf365e870fd..97144acb936f53 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1038,6 +1038,7 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) PyUnicode_InternInPlace(&name); if (tp->tp_setattro != NULL) { + 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..e13114db69b0e3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -228,6 +228,23 @@ 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_XSETREF(method_cache[h].name, Py_None); + method_cache[h].value = NULL; + } +} + void _PyType_Fini(void) { From 522898b8cee230399375b5b167b156a80f38e128 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 6 May 2019 16:27:45 +0200 Subject: [PATCH 2/4] Missing Py_INCREF --- Objects/typeobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e13114db69b0e3..a8c5a65d519b69 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -239,8 +239,10 @@ PyType_InvalidateCache(PyObject *type, PyObject *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) + if (method_cache[h].name != Py_None) { + Py_INCREF(Py_None); Py_XSETREF(method_cache[h].name, Py_None); + } method_cache[h].value = NULL; } } From 2618d293fd0d44d28e7c95e7f394c831081eded9 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 6 May 2019 17:33:45 +0200 Subject: [PATCH 3/4] Only invalidate type cache for types. --- Objects/object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/object.c b/Objects/object.c index 97144acb936f53..3e2b16cd6363e1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1038,7 +1038,8 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) PyUnicode_InternInPlace(&name); if (tp->tp_setattro != NULL) { - PyType_InvalidateCache(v, name); + if (PyType_CheckExact(v)) + PyType_InvalidateCache(v, name); err = (*tp->tp_setattro)(v, name, value); Py_DECREF(name); return err; From 11081bc0261611c55701278084776d39bedf99ce Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Mon, 6 May 2019 18:16:54 +0200 Subject: [PATCH 4/4] Add news entry. --- .../Core and Builtins/2019-05-06-18-16-42.bpo-28866.4ibrlG.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-05-06-18-16-42.bpo-28866.4ibrlG.rst 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.