Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e972c13

Browse files
authored
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%)
1 parent 9df1002 commit e972c13

2 files changed

Lines changed: 9 additions & 28 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The C function ``property_descr_get()`` uses a "cached" tuple to optimize
2+
function calls. But this tuple can be discovered in debug mode with
3+
:func:`sys.getobjects()`. Remove the optimization, it's not really worth it
4+
and it causes 3 different crashes last years.

Objects/descrobject.c

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,42 +1331,19 @@ property_dealloc(PyObject *self)
13311331
static PyObject *
13321332
property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
13331333
{
1334-
static PyObject * volatile cached_args = NULL;
1335-
PyObject *args;
1336-
PyObject *ret;
1337-
propertyobject *gs = (propertyobject *)self;
1338-
13391334
if (obj == NULL || obj == Py_None) {
13401335
Py_INCREF(self);
13411336
return self;
13421337
}
1338+
1339+
propertyobject *gs = (propertyobject *)self;
13431340
if (gs->prop_get == NULL) {
13441341
PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
13451342
return NULL;
13461343
}
1347-
args = cached_args;
1348-
cached_args = NULL;
1349-
if (!args) {
1350-
args = PyTuple_New(1);
1351-
if (!args)
1352-
return NULL;
1353-
_PyObject_GC_UNTRACK(args);
1354-
}
1355-
Py_INCREF(obj);
1356-
PyTuple_SET_ITEM(args, 0, obj);
1357-
ret = PyObject_Call(gs->prop_get, args, NULL);
1358-
if (cached_args == NULL && Py_REFCNT(args) == 1) {
1359-
assert(PyTuple_GET_SIZE(args) == 1);
1360-
assert(PyTuple_GET_ITEM(args, 0) == obj);
1361-
cached_args = args;
1362-
Py_DECREF(obj);
1363-
}
1364-
else {
1365-
assert(Py_REFCNT(args) >= 1);
1366-
_PyObject_GC_TRACK(args);
1367-
Py_DECREF(args);
1368-
}
1369-
return ret;
1344+
1345+
PyObject *args[1] = {obj};
1346+
return _PyObject_FastCall(gs->prop_get, args, 1);
13701347
}
13711348

13721349
static int

0 commit comments

Comments
 (0)