[pypy-svn] pypy default: Write an obscure refcounting workaround for a common misusage
arigo
commits-noreply at bitbucket.org
Tue Mar 15 18:10:33 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r42661:5e783074ef82
Date: 2011-03-15 13:10 -0400
http://bitbucket.org/pypy/pypy/changeset/5e783074ef82/
Log: Write an obscure refcounting workaround for a common misusage of
PyModule_AddObject().
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -92,6 +92,8 @@
self.frozen_ll2callocations = set(ll2ctypes.ALLOCATED.values())
class LeakCheckingTest(object):
+ enable_leak_checking = True
+
@staticmethod
def cleanup_references(space):
state = space.fromcache(RefcountState)
@@ -113,6 +115,10 @@
# check for sane refcnts
import gc
+ if not self.enable_leak_checking:
+ leakfinder.stop_tracking_allocations(check=False)
+ return False
+
leaking = False
state = self.space.fromcache(RefcountState)
gc.collect()
diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -4,6 +4,8 @@
import sys
class AppTestArrayModule(AppTestCpythonExtensionBase):
+ enable_leak_checking = False
+
def test_basic(self):
module = self.import_module(name='array')
arr = module.array('i', [1,2,3])
diff --git a/pypy/module/cpyext/test/test_capsule.py b/pypy/module/cpyext/test/test_capsule.py
--- a/pypy/module/cpyext/test/test_capsule.py
+++ b/pypy/module/cpyext/test/test_capsule.py
@@ -12,6 +12,7 @@
if (PyErr_Occurred()) return NULL;
module = PyImport_ImportModule("foo");
PyModule_AddObject(module, "_ptr", capsule);
+ Py_DECREF(capsule); /* XXX <--- anti-workaround */
Py_DECREF(module);
if (PyErr_Occurred()) return NULL;
Py_RETURN_NONE;
diff --git a/pypy/module/cpyext/src/modsupport.c b/pypy/module/cpyext/src/modsupport.c
--- a/pypy/module/cpyext/src/modsupport.c
+++ b/pypy/module/cpyext/src/modsupport.c
@@ -665,10 +665,12 @@
return tmp;
}
-int
-PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
+/* returns -1 in case of error, 0 if a new key was added, 1 if the key
+ was already there (and replaced) */
+static int
+_PyModule_AddObject_NoConsumeRef(PyObject *m, const char *name, PyObject *o)
{
- PyObject *dict;
+ PyObject *dict, *prev;
if (!PyModule_Check(m)) {
PyErr_SetString(PyExc_TypeError,
"PyModule_AddObject() needs module as first arg");
@@ -688,32 +690,47 @@
PyModule_GetName(m));
return -1;
}
+ prev = PyDict_GetItemString(dict, name);
if (PyDict_SetItemString(dict, name, o))
return -1;
- Py_DECREF(o);
- return 0;
+ return prev != NULL;
+}
+
+int
+PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
+{
+ int result = _PyModule_AddObject_NoConsumeRef(m, name, o);
+ /* XXX WORKAROUND for a common misusage of PyModule_AddObject:
+ for the common case of adding a new key, we don't consume a
+ reference, but instead just leak it away. The issue is that
+ people generally don't realize that this function consumes a
+ reference, because on CPython the reference is still stored
+ on the dictionary. */
+ if (result != 0)
+ Py_DECREF(o);
+ return result < 0 ? -1 : 0;
}
int
PyModule_AddIntConstant(PyObject *m, const char *name, long value)
{
+ int result;
PyObject *o = PyInt_FromLong(value);
if (!o)
return -1;
- if (PyModule_AddObject(m, name, o) == 0)
- return 0;
+ result = _PyModule_AddObject_NoConsumeRef(m, name, o);
Py_DECREF(o);
- return -1;
+ return result < 0 ? -1 : 0;
}
int
PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
{
+ int result;
PyObject *o = PyString_FromString(value);
if (!o)
return -1;
- if (PyModule_AddObject(m, name, o) == 0)
- return 0;
+ result = _PyModule_AddObject_NoConsumeRef(m, name, o);
Py_DECREF(o);
- return -1;
+ return result < 0 ? -1 : 0;
}
diff --git a/pypy/module/cpyext/test/test_pycobject.py b/pypy/module/cpyext/test/test_pycobject.py
--- a/pypy/module/cpyext/test/test_pycobject.py
+++ b/pypy/module/cpyext/test/test_pycobject.py
@@ -12,6 +12,7 @@
if (PyErr_Occurred()) return NULL;
module = PyImport_ImportModule("foo");
PyModule_AddObject(module, "_ptr", pointer);
+ Py_DECREF(pointer); /* XXX <--- anti-workaround */
Py_DECREF(module);
if (PyErr_Occurred()) return NULL;
Py_RETURN_NONE;
More information about the Pypy-commit
mailing list