summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2018-10-01 10:03:22 (GMT)
committerGitHub <noreply@github.com>2018-10-01 10:03:22 (GMT)
commite972c13624c32d0efdceb08ff83917fb6b488525 (patch)
treeb29476556514fcb9092547df2cdc7d4e29712a20
parent9df100286b35f1f9fa85976d573981f558805b3f (diff)
downloadcpython-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.rst4
-rw-r--r--Objects/descrobject.c33
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