summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Graham <simon.graham@seequent.com>2020-10-21 14:07:16 +1300
committerSimon Graham <simon.graham@seequent.com>2020-10-29 15:31:05 +1300
commitf2ca85a03dcaed0b2e2571c687bfd78a7901c2ed (patch)
tree98c499d4d444884128e0a5efdfe7c1978f4d1cfb
parentab22e0076608f4825bf9a3ca1b6a0a6a7a670d14 (diff)
downloadnumpy-f2ca85a03dcaed0b2e2571c687bfd78a7901c2ed.tar.gz
BUG: Fixed file handle leak in array_tofile.
The dup-ed file handle created in array_tofile is now closed when PyArray_ToFile fails.
-rw-r--r--numpy/core/src/multiarray/methods.c9
-rw-r--r--numpy/core/tests/test_multiarray.py8
2 files changed, 12 insertions, 5 deletions
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index e4421b41b..634dd9bc3 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -585,7 +585,7 @@ array_tostring(PyArrayObject *self, PyObject *args, PyObject *kwds)
static PyObject *
array_tofile(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
- int own;
+ int own, res1, res2;
PyObject *file;
FILE *fd;
char *sep = "";
@@ -619,10 +619,9 @@ array_tofile(PyArrayObject *self, PyObject *args, PyObject *kwds)
if (fd == NULL) {
goto fail;
}
- if (PyArray_ToFile(self, fd, sep, format) < 0) {
- goto fail;
- }
- if (npy_PyFile_DupClose2(file, fd, orig_pos) < 0) {
+ res1 = PyArray_ToFile(self, fd, sep, format);
+ res2 = npy_PyFile_DupClose2(file, fd, orig_pos);
+ if (res1 < 0 || res2 < 0) {
goto fail;
}
if (own && npy_PyFile_CloseFile(file) < 0) {
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index d46e4ce9b..3e8da66ed 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -5048,6 +5048,14 @@ class TestIO:
s = f.read()
assert_equal(s, '1.51,2.00,3.51,4.00')
+ def test_tofile_cleanup(self):
+ x = np.zeros((10), dtype=object)
+ with open(self.filename, 'wb') as f:
+ assert_raises(IOError, lambda: x.tofile(f, sep=''))
+
+ # Dup-ed file handle should be closed or remove will fail.
+ os.remove(self.filename)
+
def test_locale(self):
with CommaDecimalPointLocale():
self.test_numbers()