diff options
author | Simon Gibbons <simongibbons@gmail.com> | 2018-11-08 20:16:34 +0000 |
---|---|---|
committer | Simon Gibbons <simongibbons@gmail.com> | 2018-11-10 11:31:52 +0000 |
commit | fbdcb5b7b38a7063357f881397ccdc546f46ec5b (patch) | |
tree | fa26c05e7de5c7ee7ff6ca44cc1caa7c98bd603f /numpy/core/include | |
parent | d0e2f1ac0c0fb4aaf791c9082cff1d6b04545410 (diff) | |
download | numpy-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.h | 30 |
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__ |