From efbff33790a9fbfe6aa83491c18091018744d750 Mon Sep 17 00:00:00 2001 From: Torsten Landschoff Date: Thu, 1 Aug 2013 23:37:30 +0200 Subject: [PATCH] Change tp_clear generation to clear to NULL. Better to crash early than to never know that the reference changed to None. See discussion here: http://article.gmane.org/gmane.comp.python.cython.devel/14833 --- Cython/Compiler/ModuleNode.py | 9 +----- tests/run/clear_to_null.pyx | 68 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 tests/run/clear_to_null.pyx diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 6f2a114..8ba8678 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -1367,7 +1367,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if py_attrs or py_buffers: self.generate_self_cast(scope, code) - code.putln("PyObject* tmp;") if base_type: # want to call it explicitly if possible so inlining can be performed @@ -1390,13 +1389,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): UtilityCode.load_cached("CallNextTpClear", "ExtensionTypes.c")) for entry in py_attrs: - name = "p->%s" % entry.cname - code.putln("tmp = ((PyObject*)%s);" % name) - if entry.is_declared_generic: - code.put_init_to_py_none(name, py_object_type, nanny=False) - else: - code.put_init_to_py_none(name, entry.type, nanny=False) - code.putln("Py_XDECREF(tmp);") + code.putln("Py_CLEAR(p->%s);" % entry.cname) for entry in py_buffers: # Note: shouldn't this call __Pyx_ReleaseBuffer ?? diff --git a/tests/run/clear_to_null.pyx b/tests/run/clear_to_null.pyx new file mode 100644 index 0000000..6e49e03 --- /dev/null +++ b/tests/run/clear_to_null.pyx @@ -0,0 +1,68 @@ +""" +Check that Cython generates a tp_clear function that actually clears object +references to NULL instead of None. + +Discussed here: http://article.gmane.org/gmane.comp.python.cython.devel/14833 +""" + +from cpython.ref cimport PyObject, Py_TYPE + +cdef class ExtensionType: + """ + Just a type which is handled by a specific C type (instead of PyObject) + to check that tp_clear works when the C pointer is of a type different + from PyObject *. + """ + + +# Pull tp_clear for PyTypeObject as I did not find another way to access it +# from Cython code. + +cdef extern from "Python.h": + ctypedef struct PyTypeObject: + void (*tp_clear)(object) + + +cdef class TpClearFixture: + """ + An extension type that has a tp_clear method generated to test that it + actually clears the references to NULL. + + >>> fixture = TpClearFixture() + >>> isinstance(fixture.extension_type, ExtensionType) + True + >>> isinstance(fixture.any_object, str) + True + >>> fixture.call_tp_clear() + >>> fixture.check_any_object_status() + 'NULL' + >>> fixture.check_extension_type_status() + 'NULL' + """ + + cdef public object any_object + cdef public ExtensionType extension_type + + def __cinit__(self): + self.any_object = "Hello World" + self.extension_type = ExtensionType() + + cpdef public call_tp_clear(self): + cdef PyTypeObject *pto = Py_TYPE(self) + pto.tp_clear(self) + + cpdef public str check_any_object_status(self): + if (self.any_object) == NULL: + return 'NULL' + elif self.any_object is None: + return 'None' + else: + return 'not cleared' + + cpdef public str check_extension_type_status(self): + if (self.any_object) == NULL: + return 'NULL' + elif self.any_object is None: + return 'None' + else: + return 'not cleared' -- 2.7.4