diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-10-01 10:03:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-01 10:03:22 (GMT) |
commit | e972c13624c32d0efdceb08ff83917fb6b488525 (patch) | |
tree | b29476556514fcb9092547df2cdc7d4e29712a20 | |
parent | 9df100286b35f1f9fa85976d573981f558805b3f (diff) | |
download | cpython-e972c13624c32d0efdceb08ff83917fb6b488525.zip cpython-e972c13624c32d0efdceb08ff83917fb6b488525.tar.gz cpython-e972c13624c32d0efdceb08ff83917fb6b488525.tar.bz2 |
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%)
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2018-09-24-17-51-15.bpo-30156.pH0j5j.rst | 4 | ||||
-rw-r--r-- | Objects/descrobject.c | 33 |
2 files changed, 9 insertions, 28 deletions
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 |