Skip to content

Commit 0c79353

Browse files
authored
[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 d4cea79)
1 parent e918b19 commit 0c79353

File tree

2 files changed

+71
-46
lines changed

2 files changed

+71
-46
lines changed
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

+67-46
Original file line numberDiff line numberDiff line change
@@ -2363,21 +2363,26 @@ _posix_free(void *module)
23632363
_posix_clear((PyObject *)module);
23642364
}
23652365

2366-
static void
2366+
static int
23672367
fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long nsec)
23682368
{
2369-
PyObject *s = _PyLong_FromTime_t(sec);
2370-
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2369+
assert(!PyErr_Occurred());
2370+
2371+
int res = -1;
23712372
PyObject *s_in_ns = NULL;
23722373
PyObject *ns_total = NULL;
23732374
PyObject *float_s = NULL;
23742375

2375-
if (!(s && ns_fractional))
2376+
PyObject *s = _PyLong_FromTime_t(sec);
2377+
PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2378+
if (!(s && ns_fractional)) {
23762379
goto exit;
2380+
}
23772381

23782382
s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
2379-
if (!s_in_ns)
2383+
if (!s_in_ns) {
23802384
goto exit;
2385+
}
23812386

23822387
ns_total = PyNumber_Add(s_in_ns, ns_fractional);
23832388
if (!ns_total)
@@ -2394,46 +2399,64 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns
23942399
s = NULL;
23952400
float_s = NULL;
23962401
ns_total = NULL;
2402+
2403+
assert(!PyErr_Occurred());
2404+
res = 0;
2405+
23972406
exit:
23982407
Py_XDECREF(s);
23992408
Py_XDECREF(ns_fractional);
24002409
Py_XDECREF(s_in_ns);
24012410
Py_XDECREF(ns_total);
24022411
Py_XDECREF(float_s);
2412+
return res;
24032413
}
24042414

24052415
/* pack a system stat C structure into the Python stat tuple
24062416
(used by posix_stat() and posix_fstat()) */
24072417
static PyObject*
24082418
_pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
24092419
{
2410-
unsigned long ansec, mnsec, cnsec;
2420+
assert(!PyErr_Occurred());
2421+
24112422
PyObject *StatResultType = get_posix_state(module)->StatResultType;
24122423
PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
2413-
if (v == NULL)
2424+
if (v == NULL) {
24142425
return NULL;
2426+
}
24152427

2416-
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
2428+
#define SET_ITEM(pos, expr) \
2429+
do { \
2430+
PyObject *obj = (expr); \
2431+
if (obj == NULL) { \
2432+
goto error; \
2433+
} \
2434+
PyStructSequence_SET_ITEM(v, (pos), obj); \
2435+
} while (0)
2436+
2437+
SET_ITEM(0, PyLong_FromLong((long)st->st_mode));
24172438
static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
24182439
"stat.st_ino is larger than unsigned long long");
2419-
PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
2440+
SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino));
24202441
#ifdef MS_WINDOWS
2421-
PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
2442+
SET_ITEM(2, PyLong_FromUnsignedLong(st->st_dev));
24222443
#else
2423-
PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
2444+
SET_ITEM(2, _PyLong_FromDev(st->st_dev));
24242445
#endif
2425-
PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink));
2446+
SET_ITEM(3, PyLong_FromLong((long)st->st_nlink));
24262447
#if defined(MS_WINDOWS)
2427-
PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0));
2428-
PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0));
2448+
SET_ITEM(4, PyLong_FromLong(0));
2449+
SET_ITEM(5, PyLong_FromLong(0));
24292450
#else
2430-
PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
2431-
PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
2451+
SET_ITEM(4, _PyLong_FromUid(st->st_uid));
2452+
SET_ITEM(5, _PyLong_FromGid(st->st_gid));
24322453
#endif
24332454
static_assert(sizeof(long long) >= sizeof(st->st_size),
24342455
"stat.st_size is larger than long long");
2435-
PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));
2456+
SET_ITEM(6, PyLong_FromLongLong(st->st_size));
24362457

2458+
// Set st_atime, st_mtime and st_ctime
2459+
unsigned long ansec, mnsec, cnsec;
24372460
#if defined(HAVE_STAT_TV_NSEC)
24382461
ansec = st->st_atim.tv_nsec;
24392462
mnsec = st->st_mtim.tv_nsec;
@@ -2449,64 +2472,62 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
24492472
#else
24502473
ansec = mnsec = cnsec = 0;
24512474
#endif
2452-
fill_time(module, v, 7, st->st_atime, ansec);
2453-
fill_time(module, v, 8, st->st_mtime, mnsec);
2454-
fill_time(module, v, 9, st->st_ctime, cnsec);
2475+
if (fill_time(module, v, 7, st->st_atime, ansec) < 0) {
2476+
goto error;
2477+
}
2478+
if (fill_time(module, v, 8, st->st_mtime, mnsec) < 0) {
2479+
goto error;
2480+
}
2481+
if (fill_time(module, v, 9, st->st_ctime, cnsec) < 0) {
2482+
goto error;
2483+
}
24552484

24562485
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2457-
PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
2458-
PyLong_FromLong((long)st->st_blksize));
2486+
SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize));
24592487
#endif
24602488
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2461-
PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
2462-
PyLong_FromLong((long)st->st_blocks));
2489+
SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks));
24632490
#endif
24642491
#ifdef HAVE_STRUCT_STAT_ST_RDEV
2465-
PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
2466-
PyLong_FromLong((long)st->st_rdev));
2492+
SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev));
24672493
#endif
24682494
#ifdef HAVE_STRUCT_STAT_ST_GEN
2469-
PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
2470-
PyLong_FromLong((long)st->st_gen));
2495+
SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen));
24712496
#endif
24722497
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
24732498
{
2474-
PyObject *val;
2475-
unsigned long bsec,bnsec;
2499+
unsigned long bsec, bnsec;
24762500
bsec = (long)st->st_birthtime;
24772501
#ifdef HAVE_STAT_TV_NSEC2
24782502
bnsec = st->st_birthtimespec.tv_nsec;
24792503
#else
24802504
bnsec = 0;
24812505
#endif
2482-
val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
2483-
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2484-
val);
2506+
SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9));
24852507
}
24862508
#endif
24872509
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
2488-
PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2489-
PyLong_FromLong((long)st->st_flags));
2510+
SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags));
24902511
#endif
24912512
#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2492-
PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX,
2493-
PyLong_FromUnsignedLong(st->st_file_attributes));
2513+
SET_ITEM(ST_FILE_ATTRIBUTES_IDX,
2514+
PyLong_FromUnsignedLong(st->st_file_attributes));
24942515
#endif
24952516
#ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2496-
PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX,
2497-
PyUnicode_FromString(st->st_fstype));
2517+
SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype));
24982518
#endif
24992519
#ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2500-
PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX,
2501-
PyLong_FromUnsignedLong(st->st_reparse_tag));
2520+
SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag));
25022521
#endif
25032522

2504-
if (PyErr_Occurred()) {
2505-
Py_DECREF(v);
2506-
return NULL;
2507-
}
2508-
2523+
assert(!PyErr_Occurred());
25092524
return v;
2525+
2526+
error:
2527+
Py_DECREF(v);
2528+
return NULL;
2529+
2530+
#undef SET_ITEM
25102531
}
25112532

25122533
/* POSIX methods */

0 commit comments

Comments
 (0)