From e972c13624c32d0efdceb08ff83917fb6b488525 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 1 Oct 2018 03:03:22 -0700 Subject: bpo-30156: Remove property_descr_get() optimization (GH-9541) property_descr_get() uses a "cached" tuple to optimize function calls. But this tuple can be discovered in debug mode with sys.getobjects(). Remove the optimization, it's not really worth it and it causes 3 different crashes last years. Microbenchmark: ./python -m perf timeit -v \ -s "from collections import namedtuple; P = namedtuple('P', 'x y'); p = P(1, 2)" \ --duplicate 1024 "p.x" Result: Mean +- std dev: [ref] 32.8 ns +- 0.8 ns -> [patch] 40.4 ns +- 1.3 ns: 1.23x slower (+23%) --- .../2018-09-24-17-51-15.bpo-30156.pH0j5j.rst | 4 +++ Objects/descrobject.c | 33 ++++------------------ 2 files changed, 9 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-09-24-17-51-15.bpo-30156.pH0j5j.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-09-24-17-51-15.bpo-30156.pH0j5j.rst b/Misc/NEWS.d/next/Core and Builtins/2018-09-24-17-51-15.bpo-30156.pH0j5j.rst new file mode 100644 index 0000000..7086ff4 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-09-24-17-51-15.bpo-30156.pH0j5j.rst @@ -0,0 +1,4 @@ +The C function ``property_descr_get()`` uses a "cached" tuple to optimize +function calls. But this tuple can be discovered in debug mode with +:func:`sys.getobjects()`. Remove the optimization, it's not really worth it +and it causes 3 different crashes last years. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index b1bee90..82afa8c 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1331,42 +1331,19 @@ property_dealloc(PyObject *self) static PyObject * property_descr_get(PyObject *self, PyObject *obj, PyObject *type) { - static PyObject * volatile cached_args = NULL; - PyObject *args; - PyObject *ret; - propertyobject *gs = (propertyobject *)self; - if (obj == NULL || obj == Py_None) { Py_INCREF(self); return self; } + + propertyobject *gs = (propertyobject *)self; if (gs->prop_get == NULL) { PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); return NULL; } - args = cached_args; - cached_args = NULL; - if (!args) { - args = PyTuple_New(1); - if (!args) - return NULL; - _PyObject_GC_UNTRACK(args); - } - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 0, obj); - ret = PyObject_Call(gs->prop_get, args, NULL); - if (cached_args == NULL && Py_REFCNT(args) == 1) { - assert(PyTuple_GET_SIZE(args) == 1); - assert(PyTuple_GET_ITEM(args, 0) == obj); - cached_args = args; - Py_DECREF(obj); - } - else { - assert(Py_REFCNT(args) >= 1); - _PyObject_GC_TRACK(args); - Py_DECREF(args); - } - return ret; + + PyObject *args[1] = {obj}; + return _PyObject_FastCall(gs->prop_get, args, 1); } static int -- cgit v0.12