summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2020-10-03 08:02:22 -0600
committerGitHub <noreply@github.com>2020-10-03 08:02:22 -0600
commite6b8b19ee832ae89289721301a4f5afcd454ec4f (patch)
treeeeb99e2e3f813b32ddcd44776418a251f21c9838 /numpy
parent48896f5ef84e1b1f89c37ab85ed256c4c68796b6 (diff)
parent0e4a4d4026e9fba72c5e063c59f243a755d8979a (diff)
downloadnumpy-e6b8b19ee832ae89289721301a4f5afcd454ec4f.tar.gz
Merge pull request #17421 from seberg/coercion-cache-leak-large-arrays
BUG: Fix memory leak in array-coercion error paths
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/array_coercion.c4
-rw-r--r--numpy/core/src/multiarray/ctors.c3
-rw-r--r--numpy/core/tests/test_array_coercion.py15
3 files changed, 20 insertions, 2 deletions
diff --git a/numpy/core/src/multiarray/array_coercion.c b/numpy/core/src/multiarray/array_coercion.c
index aae8d5141..64a06d58b 100644
--- a/numpy/core/src/multiarray/array_coercion.c
+++ b/numpy/core/src/multiarray/array_coercion.c
@@ -538,7 +538,7 @@ npy_new_coercion_cache(
cache = _coercion_cache_cache[_coercion_cache_num];
}
else {
- cache = PyObject_MALLOC(sizeof(coercion_cache_obj));
+ cache = PyMem_Malloc(sizeof(coercion_cache_obj));
}
if (cache == NULL) {
PyErr_NoMemory();
@@ -570,7 +570,7 @@ npy_unlink_coercion_cache(coercion_cache_obj *current)
_coercion_cache_num++;
}
else {
- PyObject_FREE(current);
+ PyMem_Free(current);
}
return next;
}
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 956dfd3bb..55c0a31f0 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -610,6 +610,7 @@ PyArray_AssignFromCache(PyArrayObject *self, coercion_cache_obj *cache) {
PyErr_SetString(PyExc_RuntimeError,
"Inconsistent object during array creation? "
"Content of sequences changed (cache not consumed).");
+ npy_free_coercion_cache(cache);
return -1;
}
return 0;
@@ -1467,6 +1468,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
PyErr_SetString(PyExc_TypeError,
"WRITEBACKIFCOPY used for non-array input.");
Py_DECREF(dtype);
+ npy_free_coercion_cache(cache);
return NULL;
}
@@ -1475,6 +1477,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
&PyArray_Type, dtype, ndim, dims, NULL, NULL,
flags&NPY_ARRAY_F_CONTIGUOUS, NULL);
if (ret == NULL) {
+ npy_free_coercion_cache(cache);
return NULL;
}
if (cache == NULL) {
diff --git a/numpy/core/tests/test_array_coercion.py b/numpy/core/tests/test_array_coercion.py
index e0480c7bf..79954b998 100644
--- a/numpy/core/tests/test_array_coercion.py
+++ b/numpy/core/tests/test_array_coercion.py
@@ -635,3 +635,18 @@ class TestArrayLikes:
assert arr[()] is ArrayLike
arr = np.array([ArrayLike])
assert arr[0] is ArrayLike
+
+ @pytest.mark.skipif(
+ np.dtype(np.intp).itemsize < 8, reason="Needs 64bit platform")
+ def test_too_large_array_error_paths(self):
+ """Test the error paths, including for memory leaks"""
+ arr = np.array(0, dtype="uint8")
+ # Guarantees that a contiguous copy won't work:
+ arr = np.broadcast_to(arr, 2**62)
+
+ for i in range(5):
+ # repeat, to ensure caching cannot have an effect:
+ with pytest.raises(MemoryError):
+ np.array(arr)
+ with pytest.raises(MemoryError):
+ np.array([arr])