summaryrefslogtreecommitdiff
path: root/numpy/core/include
diff options
context:
space:
mode:
authorSimon Gibbons <simongibbons@gmail.com>2018-11-08 20:16:34 +0000
committerSimon Gibbons <simongibbons@gmail.com>2018-11-10 11:31:52 +0000
commitfbdcb5b7b38a7063357f881397ccdc546f46ec5b (patch)
treefa26c05e7de5c7ee7ff6ca44cc1caa7c98bd603f /numpy/core/include
parentd0e2f1ac0c0fb4aaf791c9082cff1d6b04545410 (diff)
downloadnumpy-fbdcb5b7b38a7063357f881397ccdc546f46ec5b.tar.gz
BUG: Fix segfault when an error occurs in np.fromfile
There is a problem with the way in which we handle errors which occur in the call to `PyArray_FromFile` in `np.fromfile`. The problem here is twofold. 1. The return value isn't checked, therefore if we reach the fail block, we will attempt a DECREF on a NULL and go down in flames. 2. The cleanup code on the filepointers (most notabily the call to `npy_PyFile_DupClose2`) assumes that there is no error set to work. This PR addresses these issues 1. By adding a NULL check to the fail block to ensure we don't attempt a DECREF on a NULL. 2. By saving the error state before attempting the cleanup code on the file descriptor, and then restoring it after. Fixes: #12300
Diffstat (limited to 'numpy/core/include')
-rw-r--r--numpy/core/include/numpy/npy_3kcompat.h30
1 files changed, 30 insertions, 0 deletions
diff --git a/numpy/core/include/numpy/npy_3kcompat.h b/numpy/core/include/numpy/npy_3kcompat.h
index 3721a560b..832bc0599 100644
--- a/numpy/core/include/numpy/npy_3kcompat.h
+++ b/numpy/core/include/numpy/npy_3kcompat.h
@@ -384,6 +384,36 @@ npy_PyFile_CloseFile(PyObject *file)
}
+/* This is a copy of _PyErr_ChainExceptions
+ */
+static NPY_INLINE void
+npy_PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
+{
+ if (exc == NULL)
+ return;
+
+ if (PyErr_Occurred()) {
+ /* only py3 supports this anyway */
+ #ifdef NPY_PY3K
+ PyObject *exc2, *val2, *tb2;
+ PyErr_Fetch(&exc2, &val2, &tb2);
+ PyErr_NormalizeException(&exc, &val, &tb);
+ if (tb != NULL) {
+ PyException_SetTraceback(val, tb);
+ Py_DECREF(tb);
+ }
+ Py_DECREF(exc);
+ PyErr_NormalizeException(&exc2, &val2, &tb2);
+ PyException_SetContext(val2, val);
+ PyErr_Restore(exc2, val2, tb2);
+ #endif
+ }
+ else {
+ PyErr_Restore(exc, val, tb);
+ }
+}
+
+
/* This is a copy of _PyErr_ChainExceptions, with:
* - a minimal implementation for python 2
* - __cause__ used instead of __context__