@@ -3307,9 +3307,10 @@ os_lstat_impl(PyObject *module, path_t *path, int dir_fd)
33073307#ifdef HAVE_STATX
33083308typedef struct {
33093309 PyObject_HEAD
3310- struct statx stx ;
33113310 double atime_sec , btime_sec , ctime_sec , mtime_sec ;
33123311 dev_t rdev , dev ;
3312+ /* Assertions in posixmodule_exec rely on struct statx being at the end. */
3313+ struct statx stx ;
33133314} Py_statx_result ;
33143315
33153316#define M (attr , type , offset , doc ) \
@@ -3363,7 +3364,6 @@ pystatx_result_get_u32(PyObject *op, void *context) {
33633364 Py_statx_result * self = (Py_statx_result * ) op ;
33643365 uint16_t offset = (uintptr_t )context ;
33653366 uint32_t val ;
3366- assert (offset + sizeof (val ) <= sizeof (Py_statx_result ));
33673367 memcpy (& val , (void * )self + offset , sizeof (val ));
33683368 return PyLong_FromUInt32 (val );
33693369}
@@ -3374,7 +3374,6 @@ pystatx_result_get_nsec(PyObject *op, void *context)
33743374 Py_statx_result * self = (Py_statx_result * ) op ;
33753375 uint16_t offset = (uintptr_t )context ;
33763376 struct statx_timestamp val ;
3377- assert (offset + sizeof (val ) <= sizeof (Py_statx_result ));
33783377 memcpy (& val , (void * )self + offset , sizeof (val ));
33793378 _posixstate * state = PyType_GetModuleState (Py_TYPE (op ));
33803379 assert (state != NULL );
@@ -18517,6 +18516,47 @@ posixmodule_exec(PyObject *m)
1851718516#endif
1851818517
1851918518#ifdef HAVE_STATX
18519+ #ifndef NDEBUG
18520+ /* struct statx may be extended in the future. Assert that our definition
18521+ of struct statx is large enough for all the members we expose to Python.
18522+ These asserts rely on struct statx being the last member of
18523+ Py_statx_result. If you hit these asserts, upgrade your kernel
18524+ userspace API and/or libc headers. */
18525+ for (const PyMemberDef * m = pystatx_result_members ; m -> name != NULL ; ++ m ) {
18526+ Py_ssize_t size ;
18527+ switch (m -> type ) {
18528+ case Py_T_USHORT :
18529+ size = 2 ;
18530+ break ;
18531+ case Py_T_UINT :
18532+ size = 4 ;
18533+ break ;
18534+ case Py_T_ULONGLONG :
18535+ case Py_T_DOUBLE :
18536+ size = 8 ;
18537+ break ;
18538+ default :
18539+ assert (false);
18540+ }
18541+ assert (m -> offset + size <= (Py_ssize_t )sizeof (Py_statx_result ));
18542+ }
18543+
18544+ for (const PyGetSetDef * m = pystatx_result_getset ; m -> name != NULL ; ++ m ) {
18545+ uint16_t offset = (uintptr_t )m -> closure ;
18546+ Py_ssize_t size ;
18547+ if (m -> get == pystatx_result_get_u32 ) {
18548+ size = 4 ;
18549+ }
18550+ else if (m -> get == pystatx_result_get_nsec ) {
18551+ size = sizeof (struct statx_timestamp );
18552+ }
18553+ else {
18554+ assert (false);
18555+ }
18556+ assert (offset + size <= (Py_ssize_t )sizeof (Py_statx_result ));
18557+ }
18558+ #endif /* !NDEBUG */
18559+
1852018560 if (statx == NULL ) {
1852118561 PyObject * dct = PyModule_GetDict (m );
1852218562 if (dct == NULL ) {
0 commit comments