diff --git a/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst b/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst new file mode 100644 index 000000000000000..e21a758fc2eb05a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst @@ -0,0 +1,4 @@ +Fix :func:`os.stat` and :meth:`os.DirEntry.stat`: check for exceptions. +Previously, on Python built in debug mode, these functions could trigger a +fatal Python error (and abort the process) when a function succeeded with an +exception set. Patch by Victor Stinner. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 2c89a68fa57f2e6..78fb026c0121592 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2396,21 +2396,26 @@ _posix_free(void *module) _posix_clear((PyObject *)module); } -static void +static int fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) { - PyObject *s = _PyLong_FromTime_t(sec); - PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); + assert(!PyErr_Occurred()); + + int res = -1; PyObject *s_in_ns = NULL; PyObject *ns_total = NULL; PyObject *float_s = NULL; - if (!(s && ns_fractional)) + PyObject *s = _PyLong_FromTime_t(sec); + PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); + if (!(s && ns_fractional)) { goto exit; + } s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion); - if (!s_in_ns) + if (!s_in_ns) { goto exit; + } ns_total = PyNumber_Add(s_in_ns, ns_fractional); if (!ns_total) @@ -2433,12 +2438,17 @@ fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, PyStructSequence_SET_ITEM(v, ns_index, ns_total); ns_total = NULL; } + + assert(!PyErr_Occurred()); + res = 0; + exit: Py_XDECREF(s); Py_XDECREF(ns_fractional); Py_XDECREF(s_in_ns); Py_XDECREF(ns_total); Py_XDECREF(float_s); + return res; } #ifdef MS_WINDOWS @@ -2473,34 +2483,47 @@ _pystat_l128_from_l64_l64(uint64_t low, uint64_t high) static PyObject* _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) { - unsigned long ansec, mnsec, cnsec; + assert(!PyErr_Occurred()); + PyObject *StatResultType = get_posix_state(module)->StatResultType; PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType); - if (v == NULL) + if (v == NULL) { return NULL; + } + +#define SET_ITEM(pos, expr) \ + do { \ + PyObject *obj = (expr); \ + if (obj == NULL) { \ + goto error; \ + } \ + PyStructSequence_SET_ITEM(v, pos, obj); \ + } while (0) - PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); + SET_ITEM(0, PyLong_FromLong((long)st->st_mode)); #ifdef MS_WINDOWS - PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); - PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev)); + SET_ITEM(1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); + SET_ITEM(2, PyLong_FromUnsignedLongLong(st->st_dev)); #else static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), "stat.st_ino is larger than unsigned long long"); - PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); - PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); + SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino)); + SET_ITEM(2, _PyLong_FromDev(st->st_dev)); #endif - PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink)); + SET_ITEM(3, PyLong_FromLong((long)st->st_nlink)); #if defined(MS_WINDOWS) - PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0)); - PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0)); + SET_ITEM(4, PyLong_FromLong(0)); + SET_ITEM(5, PyLong_FromLong(0)); #else - PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid)); - PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid)); + SET_ITEM(4, _PyLong_FromUid(st->st_uid)); + SET_ITEM(5, _PyLong_FromGid(st->st_gid)); #endif static_assert(sizeof(long long) >= sizeof(st->st_size), "stat.st_size is larger than long long"); - PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size)); + SET_ITEM(6, PyLong_FromLongLong(st->st_size)); + // Set st_atime, st_mtime and st_ctime + unsigned long ansec, mnsec, cnsec; #if defined(HAVE_STAT_TV_NSEC) ansec = st->st_atim.tv_nsec; mnsec = st->st_mtim.tv_nsec; @@ -2516,67 +2539,67 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - fill_time(module, v, 7, 10, 13, st->st_atime, ansec); - fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); - fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); + if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) { + goto error; + } + if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) { + goto error; + } + if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) { + goto error; + } #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, - PyLong_FromLong((long)st->st_blksize)); + SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize)); #endif #ifdef HAVE_STRUCT_STAT_ST_BLOCKS - PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX, - PyLong_FromLong((long)st->st_blocks)); + SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks)); #endif #ifdef HAVE_STRUCT_STAT_ST_RDEV - PyStructSequence_SET_ITEM(v, ST_RDEV_IDX, - PyLong_FromLong((long)st->st_rdev)); + SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev)); #endif #ifdef HAVE_STRUCT_STAT_ST_GEN - PyStructSequence_SET_ITEM(v, ST_GEN_IDX, - PyLong_FromLong((long)st->st_gen)); + SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); #endif #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) { - PyObject *val; - unsigned long bsec,bnsec; + unsigned long bsec, bnsec; bsec = (long)st->st_birthtime; #ifdef HAVE_STAT_TV_NSEC2 bnsec = st->st_birthtimespec.tv_nsec; #else bnsec = 0; #endif - val = PyFloat_FromDouble(bsec + 1e-9*bnsec); - PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, - val); + SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9)); } #elif defined(MS_WINDOWS) - fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, - st->st_birthtime, st->st_birthtime_nsec); + if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + st->st_birthtime, st->st_birthtime_nsec) < 0) { + goto error; + } #endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS - PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, - PyLong_FromLong((long)st->st_flags)); + SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags)); #endif #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES - PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX, - PyLong_FromUnsignedLong(st->st_file_attributes)); + SET_ITEM(ST_FILE_ATTRIBUTES_IDX, + PyLong_FromUnsignedLong(st->st_file_attributes)); #endif #ifdef HAVE_STRUCT_STAT_ST_FSTYPE - PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX, - PyUnicode_FromString(st->st_fstype)); + SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype)); #endif #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG - PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX, - PyLong_FromUnsignedLong(st->st_reparse_tag)); + SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag)); #endif - if (PyErr_Occurred()) { - Py_DECREF(v); - return NULL; - } - + assert(!PyErr_Occurred()); return v; + +error: + Py_DECREF(v); + return NULL; + +#undef SET_ITEM } /* POSIX methods */