summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-09-21 18:00:38 (GMT)
committerGitHub <noreply@github.com>2023-09-21 18:00:38 (GMT)
commit0c79353e1154eeb6a8a46e42a1a5d6884bd3f2ab (patch)
tree2effa7cd2ffa2270d3ca3193bed30e1280769f25 /Modules
parente918b19f420740fbc19bf29975362178d97ab209 (diff)
downloadcpython-0c79353e1154eeb6a8a46e42a1a5d6884bd3f2ab.zip
cpython-0c79353e1154eeb6a8a46e42a1a5d6884bd3f2ab.tar.gz
cpython-0c79353e1154eeb6a8a46e42a1a5d6884bd3f2ab.tar.bz2
[3.11] gh-109613: _pystat_fromstructstat() checks for exceptions (#109618) (#109668)
gh-109613: _pystat_fromstructstat() checks for exceptions (#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 d4cea794a7b9b745817d2bd982d35412aef04710)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/posixmodule.c113
1 files changed, 67 insertions, 46 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 7c5c213..2e4a66a 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -2363,21 +2363,26 @@ _posix_free(void *module)
_posix_clear((PyObject *)module);
}
-static void
+static int
fill_time(PyObject *module, PyObject *v, int 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)
@@ -2394,12 +2399,17 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns
s = NULL;
float_s = NULL;
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;
}
/* pack a system stat C structure into the Python stat tuple
@@ -2407,33 +2417,46 @@ exit:
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;
+ }
- 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));
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));
+ SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
#ifdef MS_WINDOWS
- PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
+ SET_ITEM(2, PyLong_FromUnsignedLong(st->st_dev));
#else
- PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
+ 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;
@@ -2449,64 +2472,62 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
#else
ansec = mnsec = cnsec = 0;
#endif
- fill_time(module, v, 7, st->st_atime, ansec);
- fill_time(module, v, 8, st->st_mtime, mnsec);
- fill_time(module, v, 9, st->st_ctime, cnsec);
+ if (fill_time(module, v, 7, st->st_atime, ansec) < 0) {
+ goto error;
+ }
+ if (fill_time(module, v, 8, st->st_mtime, mnsec) < 0) {
+ goto error;
+ }
+ if (fill_time(module, v, 9, 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
#ifdef 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));
}
#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 */