Skip to content

Commit 47e96c6

Browse files
[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 d4cea79) Co-authored-by: Victor Stinner <[email protected]>
1 parent dc70d30 commit 47e96c6

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
@@ -2385,21 +2385,26 @@ _posix_free(void *module)
23852385
_posix_clear((PyObject *)module);
23862386
}
23872387

2388-
static void
2388+
static int
23892389
fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec)
23902390
{
2391-
PyObject *s = _PyLong_FromTime_t(sec);
2392-
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2391+
assert(!PyErr_Occurred());
2392+
2393+
int res = -1;
23932394
PyObject *s_in_ns = NULL;
23942395
PyObject *ns_total = NULL;
23952396
PyObject *float_s = NULL;
23962397

2397-
if (!(s && ns_fractional))
2398+
PyObject *s = _PyLong_FromTime_t(sec);
2399+
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2400+
if (!(s && ns_fractional)) {
23982401
goto exit;
2402+
}
23992403

24002404
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
2401-
if (!s_in_ns)
2405+
if (!s_in_ns) {
24022406
goto exit;
2407+
}
24032408

24042409
ns_total = PyNumber_Add(s_in_ns, ns_fractional);
24052410
if (!ns_total)
@@ -2422,12 +2427,17 @@ fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index,
24222427
PyStructSequence_SET_ITEM(v, ns_index, ns_total);
24232428
ns_total = NULL;
24242429
}
2430+
2431+
assert(!PyErr_Occurred());
2432+
res = 0;
2433+
24252434
exit:
24262435
Py_XDECREF(s);
24272436
Py_XDECREF(ns_fractional);
24282437
Py_XDECREF(s_in_ns);
24292438
Py_XDECREF(ns_total);
24302439
Py_XDECREF(float_s);
2440+
return res;
24312441
}
24322442

24332443
#ifdef MS_WINDOWS
@@ -2462,34 +2472,47 @@ _pystat_l128_from_l64_l64(uint64_t low, uint64_t high)
24622472
static PyObject*
24632473
_pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
24642474
{
2465-
unsigned long ansec, mnsec, cnsec;
2475+
assert(!PyErr_Occurred());
2476+
24662477
PyObject *StatResultType = get_posix_state(module)->StatResultType;
24672478
PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
2468-
if (v == NULL)
2479+
if (v == NULL) {
24692480
return NULL;
2481+
}
2482+
2483+
#define SET_ITEM(pos, expr) \
2484+
do { \
2485+
PyObject *obj = (expr); \
2486+
if (obj == NULL) { \
2487+
goto error; \
2488+
} \
2489+
PyStructSequence_SET_ITEM(v, (pos), obj); \
2490+
} while (0)
24702491

2471-
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
2492+
SET_ITEM(0, PyLong_FromLong((long)st->st_mode));
24722493
#ifdef MS_WINDOWS
2473-
PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high));
2474-
PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev));
2494+
SET_ITEM(1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high));
2495+
SET_ITEM(2, PyLong_FromUnsignedLongLong(st->st_dev));
24752496
#else
24762497
static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
24772498
"stat.st_ino is larger than unsigned long long");
2478-
PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
2479-
PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
2499+
SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
2500+
SET_ITEM(2, _PyLong_FromDev(st->st_dev));
24802501
#endif
2481-
PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink));
2502+
SET_ITEM(3, PyLong_FromLong((long)st->st_nlink));
24822503
#if defined(MS_WINDOWS)
2483-
PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0));
2484-
PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0));
2504+
SET_ITEM(4, PyLong_FromLong(0));
2505+
SET_ITEM(5, PyLong_FromLong(0));
24852506
#else
2486-
PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
2487-
PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
2507+
SET_ITEM(4, _PyLong_FromUid(st->st_uid));
2508+
SET_ITEM(5, _PyLong_FromGid(st->st_gid));
24882509
#endif
24892510
static_assert(sizeof(long long) >= sizeof(st->st_size),
24902511
"stat.st_size is larger than long long");
2491-
PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));
2512+
SET_ITEM(6, PyLong_FromLongLong(st->st_size));
24922513

2514+
// Set st_atime, st_mtime and st_ctime
2515+
unsigned long ansec, mnsec, cnsec;
24932516
#if defined(HAVE_STAT_TV_NSEC)
24942517
ansec = st->st_atim.tv_nsec;
24952518
mnsec = st->st_mtim.tv_nsec;
@@ -2505,67 +2528,67 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
25052528
#else
25062529
ansec = mnsec = cnsec = 0;
25072530
#endif
2508-
fill_time(module, v, 7, 10, 13, st->st_atime, ansec);
2509-
fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec);
2510-
fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec);
2531+
if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) {
2532+
goto error;
2533+
}
2534+
if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) {
2535+
goto error;
2536+
}
2537+
if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) {
2538+
goto error;
2539+
}
25112540

25122541
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2513-
PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
2514-
PyLong_FromLong((long)st->st_blksize));
2542+
SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize));
25152543
#endif
25162544
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2517-
PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
2518-
PyLong_FromLong((long)st->st_blocks));
2545+
SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks));
25192546
#endif
25202547
#ifdef HAVE_STRUCT_STAT_ST_RDEV
2521-
PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
2522-
PyLong_FromLong((long)st->st_rdev));
2548+
SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev));
25232549
#endif
25242550
#ifdef HAVE_STRUCT_STAT_ST_GEN
2525-
PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
2526-
PyLong_FromLong((long)st->st_gen));
2551+
SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen));
25272552
#endif
25282553
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
25292554
{
2530-
PyObject *val;
2531-
unsigned long bsec,bnsec;
2555+
unsigned long bsec, bnsec;
25322556
bsec = (long)st->st_birthtime;
25332557
#ifdef HAVE_STAT_TV_NSEC2
25342558
bnsec = st->st_birthtimespec.tv_nsec;
25352559
#else
25362560
bnsec = 0;
25372561
#endif
2538-
val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
2539-
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2540-
val);
2562+
SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9));
25412563
}
25422564
#elif defined(MS_WINDOWS)
2543-
fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
2544-
st->st_birthtime, st->st_birthtime_nsec);
2565+
if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX,
2566+
st->st_birthtime, st->st_birthtime_nsec) < 0) {
2567+
goto error;
2568+
}
25452569
#endif
25462570
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2547-
PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2548-
PyLong_FromLong((long)st->st_flags));
2571+
SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags));
25492572
#endif
25502573
#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2551-
PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX,
2552-
PyLong_FromUnsignedLong(st->st_file_attributes));
2574+
SET_ITEM(ST_FILE_ATTRIBUTES_IDX,
2575+
PyLong_FromUnsignedLong(st->st_file_attributes));
25532576
#endif
25542577
#ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2555-
PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX,
2556-
PyUnicode_FromString(st->st_fstype));
2578+
SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype));
25572579
#endif
25582580
#ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2559-
PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX,
2560-
PyLong_FromUnsignedLong(st->st_reparse_tag));
2581+
SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag));
25612582
#endif
25622583

2563-
if (PyErr_Occurred()) {
2564-
Py_DECREF(v);
2565-
return NULL;
2566-
}
2567-
2584+
assert(!PyErr_Occurred());
25682585
return v;
2586+
2587+
error:
2588+
Py_DECREF(v);
2589+
return NULL;
2590+
2591+
#undef SET_ITEM
25692592
}
25702593

25712594
/* POSIX methods */

0 commit comments

Comments
 (0)