summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2014-04-26 18:49:48 +0200
committerStefan Behnel <stefan_ml@behnel.de>2014-04-26 18:49:48 +0200
commit68f9263017f4ea71940114d7a0669814ae15d01b (patch)
tree9dc724b4bd53d1aa30cb867d30f1030abfae6354
parent58c7a8995b329f68a2a15d229fe0bac2a2b4cd4b (diff)
downloadcython-68f9263017f4ea71940114d7a0669814ae15d01b.tar.gz
fix memory leak for memory views in extension subtypes
-rw-r--r--CHANGES.rst4
-rw-r--r--Cython/Compiler/Symtab.py6
-rw-r--r--Cython/Compiler/TypeSlots.py1
-rw-r--r--tests/memoryview/memoryview_in_subclasses.pyx58
4 files changed, 68 insertions, 1 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index b05f9f93f..aea4b012d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -15,6 +15,10 @@ Features added
Bugs fixed
----------
+* Memory leak when extension subtypes add a memory view as attribute
+ to those of the parent type without having Python object attributes
+ or a user provided dealloc method.
+
* Compiler crash on readonly properties in "binding" mode.
* Auto-encoding with ``c_string_encoding=ascii`` failed in Py3.3.
diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py
index 37870cf57..8db1e6db7 100644
--- a/Cython/Compiler/Symtab.py
+++ b/Cython/Compiler/Symtab.py
@@ -1768,6 +1768,7 @@ class CClassScope(ClassScope):
# method_table_cname string
# getset_table_cname string
# has_pyobject_attrs boolean Any PyObject attributes?
+ # has_memoryview_attrs boolean Any memory view attributes?
# has_cyclic_pyobject_attrs boolean Any PyObject attributes that may need GC?
# property_entries [Entry]
# defined boolean Defined in .pxd file
@@ -1777,6 +1778,7 @@ class CClassScope(ClassScope):
is_c_class_scope = 1
has_pyobject_attrs = False
+ has_memoryview_attrs = False
has_cyclic_pyobject_attrs = False
defined = False
implemented = False
@@ -1850,7 +1852,9 @@ class CClassScope(ClassScope):
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
- if type.is_pyobject and name != '__weakref__':
+ if type.is_memoryviewslice:
+ self.has_memoryview_attrs = True
+ elif type.is_pyobject and name != '__weakref__':
self.has_pyobject_attrs = True
if (not type.is_builtin_type
or not type.scope or type.scope.needs_gc()):
diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py
index 6595cf514..176160226 100644
--- a/Cython/Compiler/TypeSlots.py
+++ b/Cython/Compiler/TypeSlots.py
@@ -353,6 +353,7 @@ class ConstructorSlot(InternalMethodSlot):
if (self.slot_name != 'tp_new'
and scope.parent_type.base_type
and not scope.has_pyobject_attrs
+ and not scope.has_memoryview_attrs
and not scope.lookup_here(self.method)):
# if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent
diff --git a/tests/memoryview/memoryview_in_subclasses.pyx b/tests/memoryview/memoryview_in_subclasses.pyx
new file mode 100644
index 000000000..900cddb4a
--- /dev/null
+++ b/tests/memoryview/memoryview_in_subclasses.pyx
@@ -0,0 +1,58 @@
+"""
+Test for memory leaks when adding more memory view attributes in subtypes.
+"""
+
+import gc
+
+from cython.view cimport array
+
+
+def count_memoryviews():
+ gc.collect()
+ return sum([1 if 'memoryview' in str(type(o)) else 0
+ for o in gc.get_objects()])
+
+
+def run_test(cls, num_iters):
+ orig_count = count_memoryviews()
+ def f():
+ x = cls(1024)
+ for i in range(num_iters):
+ f()
+ return count_memoryviews() - orig_count
+
+
+cdef class BaseType:
+ """
+ >>> run_test(BaseType, 10)
+ 0
+ """
+ cdef double[:] buffer
+
+ def __cinit__(self, n):
+ self.buffer = array((n,), sizeof(double), 'd')
+
+
+cdef class Subtype(BaseType):
+ """
+ >>> run_test(Subtype, 10)
+ 0
+ """
+ cdef double[:] buffer2
+
+ def __cinit__(self, n):
+ self.buffer2 = array((n,), sizeof(double), 'd')
+
+
+cdef class SubtypeWithUserDealloc(BaseType):
+ """
+ >>> run_test(SubtypeWithUserDealloc, 10)
+ 0
+ """
+ cdef double[:] buffer2
+
+ def __cinit__(self, n):
+ self.buffer2 = array((n,), sizeof(double), 'd')
+
+ def __dealloc__(self):
+ pass