From 2eef5b513edd17e12e15df7f797b1ac7aed77b07 Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Tue, 10 Sep 2019 02:22:12 -0700 Subject: BUG: Fix _ctypes class cirular reference. (#13808) In _ctypes class, ctypes.cast() was called twice. It causes circular reference for _ctypes._data due to the CPython bug https://bugs.python.org/issue12836. --- numpy/core/_internal.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index b0ea603e1..7ef879554 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -294,8 +294,7 @@ class _ctypes(object): if ctypes: self._ctypes = ctypes # get a void pointer to the buffer, which keeps the array alive - self._data = _get_void_ptr(array) - assert self._data.value == ptr + self._data = self._ctypes.c_void_p(ptr) else: # fake a pointer-like object that holds onto the reference self._ctypes = _missing_ctypes() @@ -317,7 +316,9 @@ class _ctypes(object): The returned pointer will keep a reference to the array. """ - return self._ctypes.cast(self._data, obj) + ptr = self._ctypes.cast(self._data, obj) + ptr._arr = self._arr + return ptr def shape_as(self, obj): """ -- cgit v1.2.1 From 857a48654942cc8e8086577757d4f981cf6be544 Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Tue, 10 Sep 2019 13:32:33 -0700 Subject: BUG: _ctypes._as_parameter_ did not hold the array object --- numpy/core/_internal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 7ef879554..1be2a95b2 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -386,7 +386,7 @@ class _ctypes(object): Enables `c_func(some_array.ctypes)` """ - return self._data + return self.data_as(ctpyes.c_void_p) # kept for compatibility get_data = data.fget -- cgit v1.2.1 From ce24b2e585635f62c7187e0c5eaa675bb6a94e84 Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Tue, 10 Sep 2019 15:38:14 -0700 Subject: BUG: typo in _ctypes class --- numpy/core/_internal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 1be2a95b2..28cbcc810 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -386,7 +386,7 @@ class _ctypes(object): Enables `c_func(some_array.ctypes)` """ - return self.data_as(ctpyes.c_void_p) + return self.data_as(ctypes.c_void_p) # kept for compatibility get_data = data.fget -- cgit v1.2.1 From 7cc8bfb32f8f26d47cae4b342c009ab13cfb313b Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Sun, 15 Sep 2019 18:23:50 -0700 Subject: MAINT: Remove _get_void_ptr function --- numpy/core/_internal.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 28cbcc810..7b8ab9215 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -271,29 +271,12 @@ class _unsafe_first_element_pointer(object): return i -def _get_void_ptr(arr): - """ - Get a `ctypes.c_void_p` to arr.data, that keeps a reference to the array - """ - import numpy as np - # convert to a 0d array that has a data pointer referrign to the start - # of arr. This holds a reference to arr. - simple_arr = np.asarray(_unsafe_first_element_pointer(arr)) - - # create a `char[0]` using the same memory. - c_arr = (ctypes.c_char * 0).from_buffer(simple_arr) - - # finally cast to void* - return ctypes.cast(ctypes.pointer(c_arr), ctypes.c_void_p) - - class _ctypes(object): def __init__(self, array, ptr=None): self._arr = array if ctypes: self._ctypes = ctypes - # get a void pointer to the buffer, which keeps the array alive self._data = self._ctypes.c_void_p(ptr) else: # fake a pointer-like object that holds onto the reference @@ -316,6 +299,10 @@ class _ctypes(object): The returned pointer will keep a reference to the array. """ + # _ctypes.cast function causes a circular reference of self._data in + # self._data._objects. Attributes of self._data cannot be released + # until gc.collect is called. Make a copy of the pointer first then let + # it hold the array reference. ptr = self._ctypes.cast(self._data, obj) ptr._arr = self._arr return ptr -- cgit v1.2.1 From 001c43bb5f250ff7ad5d350046e4ef7ac6c202db Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Thu, 19 Sep 2019 09:16:17 -0700 Subject: TEST: Fix broken pypy ctypes test --- numpy/core/_internal.py | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 7b8ab9215..1cd6cd17f 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -247,30 +247,6 @@ class _missing_ctypes(object): self.value = ptr -class _unsafe_first_element_pointer(object): - """ - Helper to allow viewing an array as a ctypes pointer to the first element - - This avoids: - * dealing with strides - * `.view` rejecting object-containing arrays - * `memoryview` not supporting overlapping fields - """ - def __init__(self, arr): - self.base = arr - - @property - def __array_interface__(self): - i = dict( - shape=(), - typestr='|V0', - data=(self.base.__array_interface__['data'][0], False), - strides=(), - version=3, - ) - return i - - class _ctypes(object): def __init__(self, array, ptr=None): self._arr = array -- cgit v1.2.1 From 53dd7d6a706f5d9e93b41f714b46c6d32b085aec Mon Sep 17 00:00:00 2001 From: Qiming Sun Date: Sat, 5 Oct 2019 14:07:23 -0700 Subject: MAINT: Refer numpy issue #13808 to upstream CPython bug https://bugs.python.org/issue12836 --- numpy/core/_internal.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 1cd6cd17f..5fd643505 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -278,7 +278,8 @@ class _ctypes(object): # _ctypes.cast function causes a circular reference of self._data in # self._data._objects. Attributes of self._data cannot be released # until gc.collect is called. Make a copy of the pointer first then let - # it hold the array reference. + # it hold the array reference. This is a workaround to circumvent the + # CPython bug https://bugs.python.org/issue12836 ptr = self._ctypes.cast(self._data, obj) ptr._arr = self._arr return ptr -- cgit v1.2.1 From 08b5907b62db280d028fe7508633a1abe4c5e713 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 15 Oct 2019 00:59:35 +0300 Subject: DOC: no `data_as` reference is available --- numpy/core/_internal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/core/_internal.py') diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index b0ea603e1..b241d1f9d 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -348,7 +348,7 @@ class _ctypes(object): crashing. User Beware! The value of this attribute is exactly the same as ``self._array_interface_['data'][0]``. - Note that unlike `data_as`, a reference will not be kept to the array: + Note that unlike ``data_as``, a reference will not be kept to the array: code like ``ctypes.c_void_p((a + b).ctypes.data)`` will result in a pointer to a deallocated array, and should be spelt ``(a + b).ctypes.data_as(ctypes.c_void_p)`` -- cgit v1.2.1