Skip to content

Commit d4cea79

Browse files
authored
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
1 parent 115c49a commit d4cea79

File tree

2 files changed

+76
-49
lines changed

2 files changed

+76
-49
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix :func:`os.stat` and :meth:`os.DirEntry.stat`: check for exceptions.
2+
Previously, on Python built in debug mode, these functions could trigger a
3+
fatal Python error (and abort the process) when a function succeeded with an
4+
exception set. Patch by Victor Stinner.

Modules/posixmodule.c

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,21 +2396,26 @@ _posix_free(void *module)
23962396
_posix_clear((PyObject *)module);
23972397
}
23982398

2399-
static void
2399+
static int
24002400
fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec)
24012401
{
2402-
PyObject *s = _PyLong_FromTime_t(sec);
2403-
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2402+
assert(!PyErr_Occurred());
2403+
2404+
int res = -1;
24042405
PyObject *s_in_ns = NULL;
24052406
PyObject *ns_total = NULL;
24062407
PyObject *float_s = NULL;
24072408

2408-
if (!(s && ns_fractional))
2409+
PyObject *s = _PyLong_FromTime_t(sec);
2410+
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2411+
if (!(s && ns_fractional)) {
24092412
goto exit;
2413+
}
24102414

24112415
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
2412-
if (!s_in_ns)
2416+
if (!s_in_ns) {
24132417
goto exit;
2418+
}
24142419

24152420
ns_total = PyNumber_Add(s_in_ns, ns_fractional);
24162421
if (!ns_total)
@@ -2433,12 +2438,17 @@ fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index,
24332438
PyStructSequence_SET_ITEM(v, ns_index, ns_total);
24342439
ns_total = NULL;
24352440
}
2441+
2442+
assert(!PyErr_Occurred());
2443+
res = 0;
2444+
24362445
exit:
24372446
Py_XDECREF(s);
24382447
Py_XDECREF(ns_fractional);
24392448
Py_XDECREF(s_in_ns);
24402449
Py_XDECREF(ns_total);
24412450
Py_XDECREF(float_s);
2451+
return res;
24422452
}
24432453

24442454
#ifdef MS_WINDOWS
@@ -2473,34 +2483,47 @@ _pystat_l128_from_l64_l64(uint64_t low, uint64_t high)
24732483
static PyObject*
24742484
_pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
24752485
{
2476-
unsigned long ansec, mnsec, cnsec;
2486+
assert(!PyErr_Occurred());
2487+
24772488
PyObject *StatResultType = get_posix_state(module)->StatResultType;
24782489
PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
2479-
if (v == NULL)
2490+
if (v == NULL) {
24802491
return NULL;
2492+
}
2493+
2494+
#define SET_ITEM(pos, expr) \
2495+
do { \
2496+
PyObject *obj = (expr); \
2497+
if (obj == NULL) { \
2498+
goto error; \
2499+
} \
2500+
PyStructSequence_SET_ITEM(v, (pos), obj); \
2501+
} while (0)
24812502

2482-
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
2503+
SET_ITEM(0, PyLong_FromLong((long)st->st_mode));
24832504
#ifdef MS_WINDOWS
2484-
PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high));
2485-
PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev));
2505+
SET_ITEM(1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high));
2506+
SET_ITEM(2, PyLong_FromUnsignedLongLong(st->st_dev));
24862507
#else
24872508
static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
24882509
"stat.st_ino is larger than unsigned long long");
2489-
PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
2490-
PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
2510+
SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
2511+
SET_ITEM(2, _PyLong_FromDev(st->st_dev));
24912512
#endif
2492-
PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink));
2513+
SET_ITEM(3, PyLong_FromLong((long)st->st_nlink));
24932514
#if defined(MS_WINDOWS)
2494-
PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0));
2495-
PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0));
2515+
SET_ITEM(4, PyLong_FromLong(0));
2516+
SET_ITEM(5, PyLong_FromLong(0));
24962517
#else
2497-
PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
2498-
PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
2518+
SET_ITEM(4, _PyLong_FromUid(st->st_uid));
2519+
SET_ITEM(5, _PyLong_FromGid(st->st_gid));
24992520
#endif
25002521
static_assert(sizeof(long long) >= sizeof(st->st_size),
25012522
"stat.st_size is larger than long long");
2502-
PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));
2523+
SET_ITEM(6, PyLong_FromLongLong(st->st_size));
25032524

2525+
// Set st_atime, st_mtime and st_ctime
2526+
unsigned long ansec, mnsec, cnsec;
25042527
#if defined(HAVE_STAT_TV_NSEC)
25052528
ansec = st->st_atim.tv_nsec;
25062529
mnsec = st->st_mtim.tv_nsec;
@@ -2516,67 +2539,67 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
25162539
#else
25172540
ansec = mnsec = cnsec = 0;
25182541
#endif
2519-
fill_time(module, v, 7, 10, 13, st->st_atime, ansec);
2520-
fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec);
2521-
fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec);
2542+
if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) {
2543+
goto error;
2544+
}
2545+
if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) {
2546+
goto error;
2547+
}
2548+
if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) {
2549+
goto error;
2550+
}
25222551

25232552
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2524-
PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
2525-
PyLong_FromLong((long)st->st_blksize));
2553+
SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize));
25262554
#endif
25272555
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2528-
PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
2529-
PyLong_FromLong((long)st->st_blocks));
2556+
SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks));
25302557
#endif
25312558
#ifdef HAVE_STRUCT_STAT_ST_RDEV
2532-
PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
2533-
PyLong_FromLong((long)st->st_rdev));
2559+
SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev));
25342560
#endif
25352561
#ifdef HAVE_STRUCT_STAT_ST_GEN
2536-
PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
2537-
PyLong_FromLong((long)st->st_gen));
2562+
SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen));
25382563
#endif
25392564
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
25402565
{
2541-
PyObject *val;
2542-
unsigned long bsec,bnsec;
2566+
unsigned long bsec, bnsec;
25432567
bsec = (long)st->st_birthtime;
25442568
#ifdef HAVE_STAT_TV_NSEC2
25452569
bnsec = st->st_birthtimespec.tv_nsec;
25462570
#else
25472571
bnsec = 0;
25482572
#endif
2549-
val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
2550-
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2551-
val);
2573+
SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9));
25522574
}
25532575
#elif defined(MS_WINDOWS)
2554-
fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
2555-
st->st_birthtime, st->st_birthtime_nsec);
2576+
if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
2577+
st->st_birthtime, st->st_birthtime_nsec) < 0) {
2578+
goto error;
2579+
}
25562580
#endif
25572581
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2558-
PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2559-
PyLong_FromLong((long)st->st_flags));
2582+
SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags));
25602583
#endif
25612584
#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2562-
PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX,
2563-
PyLong_FromUnsignedLong(st->st_file_attributes));
2585+
SET_ITEM(ST_FILE_ATTRIBUTES_IDX,
2586+
PyLong_FromUnsignedLong(st->st_file_attributes));
25642587
#endif
25652588
#ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2566-
PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX,
2567-
PyUnicode_FromString(st->st_fstype));
2589+
SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype));
25682590
#endif
25692591
#ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2570-
PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX,
2571-
PyLong_FromUnsignedLong(st->st_reparse_tag));
2592+
SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag));
25722593
#endif
25732594

2574-
if (PyErr_Occurred()) {
2575-
Py_DECREF(v);
2576-
return NULL;
2577-
}
2578-
2595+
assert(!PyErr_Occurred());
25792596
return v;
2597+
2598+
error:
2599+
Py_DECREF(v);
2600+
return NULL;
2601+
2602+
#undef SET_ITEM
25802603
}
25812604

25822605
/* POSIX methods */

0 commit comments

Comments
 (0)