[3.12] gh-109613: _pystat_fromstructstat() checks for exceptions (GH-109618) (#109641)

gh-109613: _pystat_fromstructstat() checks for exceptions (GH-109618)

Fix os.stat() and 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.

_pystat_fromstructstat() now exits immediately if an exception is
raised, rather only checking for exceptions at the end. It fix
following fatal error in fill_time():

    Fatal Python error: _Py_CheckSlotResult:
    Slot * of type int succeeded with an exception set
(cherry picked from commit d4cea794a7)

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Miss Islington (bot) 2023-10-02 08:09:45 -07:00 committed by GitHub
parent dc70d30732
commit 47e96c6782
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 49 deletions

View file

@ -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.

View file

@ -2385,21 +2385,26 @@ _posix_free(void *module)
_posix_clear((PyObject *)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) 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); assert(!PyErr_Occurred());
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
int res = -1;
PyObject *s_in_ns = NULL; PyObject *s_in_ns = NULL;
PyObject *ns_total = NULL; PyObject *ns_total = NULL;
PyObject *float_s = 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; goto exit;
}
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion); s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
if (!s_in_ns) if (!s_in_ns) {
goto exit; goto exit;
}
ns_total = PyNumber_Add(s_in_ns, ns_fractional); ns_total = PyNumber_Add(s_in_ns, ns_fractional);
if (!ns_total) if (!ns_total)
@ -2422,12 +2427,17 @@ fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index,
PyStructSequence_SET_ITEM(v, ns_index, ns_total); PyStructSequence_SET_ITEM(v, ns_index, ns_total);
ns_total = NULL; ns_total = NULL;
} }
assert(!PyErr_Occurred());
res = 0;
exit: exit:
Py_XDECREF(s); Py_XDECREF(s);
Py_XDECREF(ns_fractional); Py_XDECREF(ns_fractional);
Py_XDECREF(s_in_ns); Py_XDECREF(s_in_ns);
Py_XDECREF(ns_total); Py_XDECREF(ns_total);
Py_XDECREF(float_s); Py_XDECREF(float_s);
return res;
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
@ -2462,34 +2472,47 @@ _pystat_l128_from_l64_l64(uint64_t low, uint64_t high)
static PyObject* static PyObject*
_pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
{ {
unsigned long ansec, mnsec, cnsec; assert(!PyErr_Occurred());
PyObject *StatResultType = get_posix_state(module)->StatResultType; PyObject *StatResultType = get_posix_state(module)->StatResultType;
PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType); PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
if (v == NULL) if (v == NULL) {
return NULL; return NULL;
}
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); #define SET_ITEM(pos, expr) \
do { \
PyObject *obj = (expr); \
if (obj == NULL) { \
goto error; \
} \
PyStructSequence_SET_ITEM(v, (pos), obj); \
} while (0)
SET_ITEM(0, PyLong_FromLong((long)st->st_mode));
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); SET_ITEM(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(2, PyLong_FromUnsignedLongLong(st->st_dev));
#else #else
static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
"stat.st_ino is larger than unsigned long long"); "stat.st_ino is larger than unsigned long long");
PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); SET_ITEM(2, _PyLong_FromDev(st->st_dev));
#endif #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) #if defined(MS_WINDOWS)
PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0)); SET_ITEM(4, PyLong_FromLong(0));
PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0)); SET_ITEM(5, PyLong_FromLong(0));
#else #else
PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid)); SET_ITEM(4, _PyLong_FromUid(st->st_uid));
PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid)); SET_ITEM(5, _PyLong_FromGid(st->st_gid));
#endif #endif
static_assert(sizeof(long long) >= sizeof(st->st_size), static_assert(sizeof(long long) >= sizeof(st->st_size),
"stat.st_size is larger than long long"); "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) #if defined(HAVE_STAT_TV_NSEC)
ansec = st->st_atim.tv_nsec; ansec = st->st_atim.tv_nsec;
mnsec = st->st_mtim.tv_nsec; mnsec = st->st_mtim.tv_nsec;
@ -2505,67 +2528,67 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
#else #else
ansec = mnsec = cnsec = 0; ansec = mnsec = cnsec = 0;
#endif #endif
fill_time(module, v, 7, 10, 13, st->st_atime, ansec); if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) {
fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); goto error;
fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); }
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 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize));
PyLong_FromLong((long)st->st_blksize));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX, SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks));
PyLong_FromLong((long)st->st_blocks));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_RDEV #ifdef HAVE_STRUCT_STAT_ST_RDEV
PyStructSequence_SET_ITEM(v, ST_RDEV_IDX, SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev));
PyLong_FromLong((long)st->st_rdev));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_GEN #ifdef HAVE_STRUCT_STAT_ST_GEN
PyStructSequence_SET_ITEM(v, ST_GEN_IDX, SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen));
PyLong_FromLong((long)st->st_gen));
#endif #endif
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
{ {
PyObject *val; unsigned long bsec, bnsec;
unsigned long bsec,bnsec;
bsec = (long)st->st_birthtime; bsec = (long)st->st_birthtime;
#ifdef HAVE_STAT_TV_NSEC2 #ifdef HAVE_STAT_TV_NSEC2
bnsec = st->st_birthtimespec.tv_nsec; bnsec = st->st_birthtimespec.tv_nsec;
#else #else
bnsec = 0; bnsec = 0;
#endif #endif
val = PyFloat_FromDouble(bsec + 1e-9*bnsec); SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9));
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
val);
} }
#elif defined(MS_WINDOWS) #elif defined(MS_WINDOWS)
fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
st->st_birthtime, st->st_birthtime_nsec); st->st_birthtime, st->st_birthtime_nsec) < 0) {
goto error;
}
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_FLAGS #ifdef HAVE_STRUCT_STAT_ST_FLAGS
PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags));
PyLong_FromLong((long)st->st_flags));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX, SET_ITEM(ST_FILE_ATTRIBUTES_IDX,
PyLong_FromUnsignedLong(st->st_file_attributes)); PyLong_FromUnsignedLong(st->st_file_attributes));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_FSTYPE #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX, SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype));
PyUnicode_FromString(st->st_fstype));
#endif #endif
#ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX, SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag));
PyLong_FromUnsignedLong(st->st_reparse_tag));
#endif #endif
if (PyErr_Occurred()) { assert(!PyErr_Occurred());
return v;
error:
Py_DECREF(v); Py_DECREF(v);
return NULL; return NULL;
}
return v; #undef SET_ITEM
} }
/* POSIX methods */ /* POSIX methods */