diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2020-10-03 08:02:22 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-03 08:02:22 -0600 |
commit | e6b8b19ee832ae89289721301a4f5afcd454ec4f (patch) | |
tree | eeb99e2e3f813b32ddcd44776418a251f21c9838 /numpy | |
parent | 48896f5ef84e1b1f89c37ab85ed256c4c68796b6 (diff) | |
parent | 0e4a4d4026e9fba72c5e063c59f243a755d8979a (diff) | |
download | numpy-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.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 3 | ||||
-rw-r--r-- | numpy/core/tests/test_array_coercion.py | 15 |
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]) |