| Message ID | 20260805080304.3535401-1-matthias.goergens@gmail.com (mailing list archive) |
|---|---|
| Headers |
Return-Path: <libc-alpha-bounces~patchwork=sourceware.org@sourceware.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 993644BB1C12 for <patchwork@sourceware.org>; Wed, 5 Aug 2026 08:07:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 993644BB1C12 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=p9SBPvZR X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by sourceware.org (Postfix) with ESMTPS id A55FC4BAE7E0 for <libc-alpha@sourceware.org>; Wed, 5 Aug 2026 08:03:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A55FC4BAE7E0 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A55FC4BAE7E0 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::432 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785916988; cv=none; b=Z9z8ckt//9n8rsk2AG64s6ksOgq0ZgFlnQW0LtGjI8RyHwIGmAfJN6sOHQqjNGqJCbWa7a2+WYLnlKjEngI1hUWgIpNuS9m8r+2qL8lW89ifpYJ8RKyyuEdvl/A55IPq7hsFF1wYm9GnUW/i1dFOrcMOnWBkLGrXIPthSHn2Byw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785916988; c=relaxed/simple; bh=Wk4/9giI961yN0xxNt2mbChq/K37ohvLw7GaysW5jQE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=UjvWB7rWRaApKsubEkji4klS+Yd741uFrKq06IaxfqNqhi9Pj6YpjZdjdMRbC2r8OQN2PLzpSrMWevf5/KOq+pzCJB9LFzlv3MNEPxkUMuVbgGkSKtEq8asgvb+LN9aaFL71nrvB6W0Ynp2h8crmQYVdWhzvMgSeahSdM0xD9ec= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=p9SBPvZR DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A55FC4BAE7E0 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-8485ef63b68so1035170b3a.1 for <libc-alpha@sourceware.org>; Wed, 05 Aug 2026 01:03:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1785916988; x=1786521788; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=WczdzhEVzUUMtv9CDke5AH3Vc/iCP26zMw9lOF0uhM8=; b=p9SBPvZRihc6tHLWXqL8xpAwQZqrwfIFC2g/O9nvC51miz455+393Xr51Qh9rmwKYW qLHfoWpGoxYbFHRGsqj9t0/GwqpVZPRhRgiDrttCwev8FPftf+UA3P5zcl0fw2Nr0lCl KHkZe20a0DlcyF8F2VMziMDuZ2gVUZ6mrqAaEyOk5DlfUngG3lFLHrjJndxkZ38280LU FsyHIpsWzftUEnJeJrKNjvunE9u8gtAqEFzeQr2c3dA1Co79lKKY++FCqjpACg0+ayRl 0Qi4bHJrSPx6M0seZMghu9sfwYKQPpQHw653cDMYsq9m9XZQuORqYMBVSUCTuu1uLkVx wFSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785916988; x=1786521788; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=WczdzhEVzUUMtv9CDke5AH3Vc/iCP26zMw9lOF0uhM8=; b=Pv+kNcfV4y7SlTw04yhvBwkYKg+Vjnt5ZmozpamN7EcoCrjecQncZKtH5KsU5C0iEl K+szFYmM5o/egYez+tLn6f3WTsIccqThcx/2xe/6VslkjVTK1mLZv4TgPypeVOYMWQUQ 6w4Fv2K4UmKc0XgQx6idUouHUuJ1Pk4Cm5rmmRvgdulBBU0VEX4O5wpYuhJFhSBcb1ix FFX3pwpPshk4AKOqYEIWTPgaQYwfdwfVJ6auVmb3376yX8T/sxpmVyQmXAY2dWGYbqjK iNx+XC3wrBicpU7qixTlPtZyyhFCVkNEzMAWoEyIpIObVHIWH6izF3tCXBcxuJPVsYTk 8cBw== X-Gm-Message-State: AOJu0YxdF6G63MEAGL9tENCv5IVCBMX4ov/orV8cjv5c4YL+eBTOiEIU uMGjaSZ1y+rdmhS5cTE7HD8Nwrkdk5mDDgqhr8QtxlpYo6txr3GH2TT0tU1ta+bI X-Gm-Gg: AR+sD116o+llECmGehgInT4BLRRnJUFjiEPW5Ia1j04o0aEQEPMp91b26AVBIMtLERU sy0IfURm26gvqlvx++65LZQa+WI6cLzs4OvS4dE7Gq7bIJj+9fhFfdLX7XJIrc+B3UwIfzdMRoX YamDQewoIezY5P8W7TAKJAV3hJ/K8n+yFn3t0dHwWVHpYlk0wbBYJ2zkfvcaAaHUeHt0kBuOWfE jMb6fUvTN8HzaiJ9o+rhj/UBcKfE90aqO3F/JLr1F6Bt9shU2cTwY86GmhQr2g1Gk8iHk1l5+Bm XCy266FGpsBDDTCOUW8k64QVJ1NeaxrF5L2OxpB1HP+9STj8uRamVdnbr0u/W7kFr8Oi8VSBuWA ANDcNigRuAO0g2G0UvxjwO/klbAUD0j0WPGMS8BNdsPkjTs+3BWn6oadLYRc1HAVdmaFt6sYNGx E5w/pUVOYfPXjkcIOj7JfqAKvGXWvcyk6eYsmZME7hjWaaCIQh0GMFSO8xx1OvS8+l7jTT55Bxy CZ78VfIxhvY7RfbbwyLrdsRpTqZih/5XCMBLR6PM9RTPaInX8yEv3bDo21OuUOedd7TBuTRH9x0 v6X7zBZOkefsbNMvsHVnDEhP8vhrT9F/UcIWDPuFyL5xm99D9ScA X-Received: by 2002:a05:6a20:72a4:b0:3bf:9142:ba3a with SMTP id adf61e73a8af0-3cb85ef7460mr5419658637.26.1785916987550; Wed, 05 Aug 2026 01:03:07 -0700 (PDT) Received: from spider.bream-herring.ts.net ([103.252.203.158]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-cbe707cab37sm973517a12.7.2026.08.05.01.03.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Aug 2026 01:03:07 -0700 (PDT) From: Matthias Goergens <matthias.goergens@gmail.com> To: libc-alpha@sourceware.org Cc: Matthias Goergens <matthias.goergens@gmail.com> Subject: [PATCH 0/2] linux: Keep time64 stat layout independent of feature macros Date: Wed, 5 Aug 2026 16:03:02 +0800 Message-ID: <20260805080304.3535401-1-matthias.goergens@gmail.com> X-Mailer: git-send-email 2.55.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_PBL, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list <libc-alpha.sourceware.org> List-Unsubscribe: <https://sourceware.org/mailman/options/libc-alpha>, <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/libc-alpha/> List-Post: <mailto:libc-alpha@sourceware.org> List-Help: <mailto:libc-alpha-request@sourceware.org?subject=help> List-Subscribe: <https://sourceware.org/mailman/listinfo/libc-alpha>, <mailto:libc-alpha-request@sourceware.org?subject=subscribe> Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org |
| Series |
linux: Keep time64 stat layout independent of feature macros
|
|
Message
Matthias Goergens
Aug. 5, 2026, 8:03 a.m. UTC
Bug 32119 reports that feature-test macros change the public time64 struct stat layout on 32-bit targets. The series separates two causes. Patch 1 includes the endian definitions used by the shared helper. Without them, strict pre-POSIX.1-2008 modes select big-endian timestamp ordering on little-endian targets. This is an unambiguous layout bug. Patch 2 removes two trailing reserved words which the helper exposes only in those strict modes. History shows that they were imported accidentally when the public and internal time64 declarations were consolidated. The stat implementation does not write them, and the default public and internal layouts omit them. Patch 2 nevertheless changes sizeof(struct stat) for 32-bit objects already compiled with both 64-bit time and strict pre-POSIX.1-2008 feature macros. Please advise whether preserving that niche accidental layout is required by glibc ABI policy. Patch 1 is independent if the size correction is unsuitable. An i386 build and the io tests pass. The regression compares timestamp offsets and sizes across translation units built in default and POSIX.1-2001 modes. Compile-time layout models also pass for 32-bit Arm, PowerPC, and MIPS; these models are supplementary and are not full cross builds. I do not have an FSF copyright assignment on file. This series is offered under the Developer Certificate of Origin 1.1, as certified by the Signed-off-by line in each commit. Matthias Goergens (2): linux: Fix time64 stat nanosecond layout in strict modes linux: Keep time64 stat size independent of feature macros [BZ #32119] io/Makefile | 15 +++++++ io/tst-stat-layout-time64-legacy.c | 41 +++++++++++++++++++ io/tst-stat-layout-time64.c | 38 +++++++++++++++++ .../linux/bits/struct_stat_time64_helper.h | 5 +-- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 io/tst-stat-layout-time64-legacy.c create mode 100644 io/tst-stat-layout-time64.c
Comments
On 05/08/26 05:03, Matthias Goergens wrote: > Bug 32119 reports that feature-test macros change the public time64 > struct stat layout on 32-bit targets. The series separates two causes. > > Patch 1 includes the endian definitions used by the shared helper. Without > them, strict pre-POSIX.1-2008 modes select big-endian timestamp ordering on > little-endian targets. This is an unambiguous layout bug. > > Patch 2 removes two trailing reserved words which the helper exposes only in > those strict modes. History shows that they were imported accidentally when > the public and internal time64 declarations were consolidated. The stat > implementation does not write them, and the default public and internal > layouts omit them. > > Patch 2 nevertheless changes sizeof(struct stat) for 32-bit objects already > compiled with both 64-bit time and strict pre-POSIX.1-2008 feature macros. > Please advise whether preserving that niche accidental layout is required by > glibc ABI policy. Patch 1 is independent if the size correction is unsuitable. I still strictly an ABI break, but I also think the blast radius is quite minimal. The fields were unused by glibc, so it would be mostly between TU built with different flags. And I do not think it would worth adding compat symbols, but I also think it would be good to backport this fix to all affected branches. > > An i386 build and the io tests pass. The regression compares timestamp > offsets and sizes across translation units built in default and POSIX.1-2001 > modes. Compile-time layout models also pass for 32-bit Arm, PowerPC, and MIPS; > these models are supplementary and are not full cross builds. I think it would be better to move this test to script that uses glibcextracy.py, so these tests can be checked in cross-compiling mode. Something like: diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 14a56d5cc3f..a5811977d4a 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -413,6 +413,17 @@ $(objpfx)tst-sched-consts.out: ../sysdeps/unix/sysv/linux/tst-sched-consts.py < /dev/null > $@ 2>&1; $(evaluate-test) $(objpfx)tst-sched-consts.out: $(sysdeps-linux-python-deps) +tests-special += \ + $(objpfx)tst-stat-layout-time64.out \ + # tests-special +$(objpfx)tst-stat-layout-time64.out: \ + ../sysdeps/unix/sysv/linux/tst-stat-layout-time64.py + $(sysdeps-linux-python) \ + ../sysdeps/unix/sysv/linux/tst-stat-layout-time64.py \ + $(sysdeps-linux-python-cc) \ + < /dev/null > $@ 2>&1; $(evaluate-test) +$(objpfx)tst-stat-layout-time64.out: $(sysdeps-linux-python-deps) + tst-rseq-disable-TUNABLES += glibc.pthread.rseq=0 tst-rseq-disable-static-TUNABLES += glibc.pthread.rseq=0 diff --git a/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py b/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py new file mode 100644 index 00000000000..2c6dd66a491 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +# Check that feature-test macros do not change the time64 stat layout. +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <https://www.gnu.org/licenses/>. + +import argparse +import sys + +import glibcextract + +MODES = { + 'POSIX.1-1996': '#define _POSIX_C_SOURCE 199506L', + 'POSIX.1-2001': '#define _POSIX_C_SOURCE 200112L', + 'POSIX.1-2008': '#define _POSIX_C_SOURCE 200809L', + 'XPG6': '#define _XOPEN_SOURCE 600', +} + + +def compute_stat_layout(cc, mode_define): + # The nanosecond members are named differently in the two helper + # branches: st_Xtim.tv_nsec with __USE_XOPEN2K8, st_Xtimensec + #otherwise. + sym_data = [ + '#undef _GNU_SOURCE', + mode_define, + '#define _TIME_BITS 64', + '#define _FILE_OFFSET_BITS 64', + '#include <stddef.h>', + '#include <sys/stat.h>', + 'START', + ('sizeof_stat', 'sizeof (struct stat)'), + ('st_dev', 'offsetof (struct stat, st_dev)'), + ('st_ino', 'offsetof (struct stat, st_ino)'), + ('st_mode', 'offsetof (struct stat, st_mode)'), + ('st_nlink', 'offsetof (struct stat, st_nlink)'), + ('st_uid', 'offsetof (struct stat, st_uid)'), + ('st_gid', 'offsetof (struct stat, st_gid)'), + ('st_rdev', 'offsetof (struct stat, st_rdev)'), + ('st_size', 'offsetof (struct stat, st_size)'), + ('st_blksize', 'offsetof (struct stat, st_blksize)'), + ('st_blocks', 'offsetof (struct stat, st_blocks)'), + ('st_atime', 'offsetof (struct stat, st_atime)'), + ('st_mtime', 'offsetof (struct stat, st_mtime)'), + ('st_ctime', 'offsetof (struct stat, st_ctime)'), + '#ifdef __USE_XOPEN2K8', + ('st_atimensec', 'offsetof (struct stat, st_atim.tv_nsec)'), + ('st_mtimensec', 'offsetof (struct stat, st_mtim.tv_nsec)'), + ('st_ctimensec', 'offsetof (struct stat, st_ctim.tv_nsec)'), + '#else', + ('st_atimensec', 'offsetof (struct stat, st_atimensec)'), + ('st_mtimensec', 'offsetof (struct stat, st_mtimensec)'), + ('st_ctimensec', 'offsetof (struct stat, st_ctimensec)'), + '#endif', + ] + return glibcextract.compute_c_consts(sym_data, cc) + + +def main(): + parser = argparse.ArgumentParser( + description='Check that feature-test macros do not change ' + 'the time64 stat layout.') + parser.add_argument('--cc', metavar='CC', + help='C compiler (including options) to use') + args = parser.parse_args() + default_layout = compute_stat_layout(args.cc, '#define _GNU_SOURCE 1') + status = 0 + for mode, mode_define in sorted(MODES.items()): + mode_layout = compute_stat_layout(args.cc, mode_define) + for name, value in default_layout.items(): + if mode_layout[name] != value: + print('FAIL: %s: %s is %s, %s in default mode' + % (mode, name, mode_layout[name], value)) + status = 1 + if status == 0: + print('PASS: struct stat layout is feature-test-macro invariant') + sys.exit(status) + + +if __name__ == '__main__': + main() And this approach uncovered a similar issue on arc and ork1, which are both 32-bit with 64-bit time_t by default. Different than riscv32, another 32-bit with 64-bit time_t, alignof(int64) == 4 and thus 'struct stat' size and internal layout (sigh...) differ. The fix would require to change de generic implementation sysdeps/unix/sysv/linux/bits/struct_stat.h: iff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h index e912c3f6ba5..cdbe1f8f762 100644 --- a/sysdeps/unix/sysv/linux/bits/struct_stat.h +++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h @@ -41,6 +41,22 @@ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name #endif +/* The pre-POSIX.1-2008 timestamp fields must match the layout of the + 'struct timespec' members used in the POSIX.1-2008 case, including the + padding required when the seconds field is wider than the word size. */ +#if __WORDSIZE == 64 \ + || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) \ + || (__TIMESIZE == 32 && !defined __USE_TIME64_REDIRECTS) +# define __fieldts(name) \ + __time_t name; unsigned long int name ## nsec +#elif __BYTE_ORDER == __BIG_ENDIAN +# define __fieldts(name) \ + __time_t name; int: 32; unsigned long int name ## nsec +#else +# define __fieldts(name) \ + __time_t name; unsigned long int name ## nsec; int: 32 +#endif + struct stat { __dev_t st_dev; /* Device. */ @@ -69,12 +85,9 @@ struct stat # define st_mtime st_mtim.tv_sec # define st_ctime st_ctim.tv_sec #else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ + __fieldts (st_atime); /* Time of last access. */ + __fieldts (st_mtime); /* Time of last modification. */ + __fieldts (st_ctime); /* Time of last status change. */ #endif int __glibc_reserved[2]; }; @@ -107,17 +120,16 @@ struct stat64 struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ #else - __time_t st_atime; /* Time of last access. */ - unsigned long int st_atimensec; /* Nscecs of last access. */ - __time_t st_mtime; /* Time of last modification. */ - unsigned long int st_mtimensec; /* Nsecs of last modification. */ - __time_t st_ctime; /* Time of last status change. */ - unsigned long int st_ctimensec; /* Nsecs of last status change. */ + __fieldts (st_atime); /* Time of last access. */ + __fieldts (st_mtime); /* Time of last modification. */ + __fieldts (st_ctime); /* Time of last status change. */ #endif int __glibc_reserved[2]; }; #endif +#undef __fieldts + /* Tell code we have these members. */ #define _STATBUF_ST_BLKSIZE #define _STATBUF_ST_RDEV I am not sure if this would require a different bug, but we will need to fix it along with BZ#34466. > > I do not have an FSF copyright assignment on file. This series is offered > under the Developer Certificate of Origin 1.1, as certified by the > Signed-off-by line in each commit. > > Matthias Goergens (2): > linux: Fix time64 stat nanosecond layout in strict modes > linux: Keep time64 stat size independent of feature macros [BZ #32119] > > io/Makefile | 15 +++++++ > io/tst-stat-layout-time64-legacy.c | 41 +++++++++++++++++++ > io/tst-stat-layout-time64.c | 38 +++++++++++++++++ > .../linux/bits/struct_stat_time64_helper.h | 5 +-- > 4 files changed, 96 insertions(+), 3 deletions(-) > create mode 100644 io/tst-stat-layout-time64-legacy.c > create mode 100644 io/tst-stat-layout-time64.c >
On 05/08/26 12:23, Adhemerval Zanella Netto wrote: > > > On 05/08/26 05:03, Matthias Goergens wrote: >> Bug 32119 reports that feature-test macros change the public time64 >> struct stat layout on 32-bit targets. The series separates two causes. >> >> Patch 1 includes the endian definitions used by the shared helper. Without >> them, strict pre-POSIX.1-2008 modes select big-endian timestamp ordering on >> little-endian targets. This is an unambiguous layout bug. >> >> Patch 2 removes two trailing reserved words which the helper exposes only in >> those strict modes. History shows that they were imported accidentally when >> the public and internal time64 declarations were consolidated. The stat >> implementation does not write them, and the default public and internal >> layouts omit them. >> >> Patch 2 nevertheless changes sizeof(struct stat) for 32-bit objects already >> compiled with both 64-bit time and strict pre-POSIX.1-2008 feature macros. >> Please advise whether preserving that niche accidental layout is required by >> glibc ABI policy. Patch 1 is independent if the size correction is unsuitable. > > I still strictly an ABI break, but I also think the blast radius is quite minimal. > The fields were unused by glibc, so it would be mostly between TU built with > different flags. > > And I do not think it would worth adding compat symbols, but I also think it > would be good to backport this fix to all affected branches. > >> >> An i386 build and the io tests pass. The regression compares timestamp >> offsets and sizes across translation units built in default and POSIX.1-2001 >> modes. Compile-time layout models also pass for 32-bit Arm, PowerPC, and MIPS; >> these models are supplementary and are not full cross builds. > > I think it would be better to move this test to script that uses glibcextracy.py, > so these tests can be checked in cross-compiling mode. Something like: > > diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile > index 14a56d5cc3f..a5811977d4a 100644 > --- a/sysdeps/unix/sysv/linux/Makefile > +++ b/sysdeps/unix/sysv/linux/Makefile > @@ -413,6 +413,17 @@ $(objpfx)tst-sched-consts.out: ../sysdeps/unix/sysv/linux/tst-sched-consts.py > < /dev/null > $@ 2>&1; $(evaluate-test) > $(objpfx)tst-sched-consts.out: $(sysdeps-linux-python-deps) > > +tests-special += \ > + $(objpfx)tst-stat-layout-time64.out \ > + # tests-special > +$(objpfx)tst-stat-layout-time64.out: \ > + ../sysdeps/unix/sysv/linux/tst-stat-layout-time64.py > + $(sysdeps-linux-python) \ > + ../sysdeps/unix/sysv/linux/tst-stat-layout-time64.py \ > + $(sysdeps-linux-python-cc) \ > + < /dev/null > $@ 2>&1; $(evaluate-test) > +$(objpfx)tst-stat-layout-time64.out: $(sysdeps-linux-python-deps) > + > tst-rseq-disable-TUNABLES += glibc.pthread.rseq=0 > tst-rseq-disable-static-TUNABLES += glibc.pthread.rseq=0 > > diff --git a/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py b/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py > new file mode 100644 > index 00000000000..2c6dd66a491 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/tst-stat-layout-time64.py > @@ -0,0 +1,94 @@ > +#!/usr/bin/python3 > +# Check that feature-test macros do not change the time64 stat layout. > +# Copyright (C) 2026 Free Software Foundation, Inc. > +# This file is part of the GNU C Library. > +# > +# The GNU C Library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > +# > +# The GNU C Library is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with the GNU C Library; if not, see > +# <https://www.gnu.org/licenses/>. > + > +import argparse > +import sys > + > +import glibcextract > + > +MODES = { > + 'POSIX.1-1996': '#define _POSIX_C_SOURCE 199506L', > + 'POSIX.1-2001': '#define _POSIX_C_SOURCE 200112L', > + 'POSIX.1-2008': '#define _POSIX_C_SOURCE 200809L', > + 'XPG6': '#define _XOPEN_SOURCE 600', > +} > + > + > +def compute_stat_layout(cc, mode_define): > + # The nanosecond members are named differently in the two helper > + # branches: st_Xtim.tv_nsec with __USE_XOPEN2K8, st_Xtimensec > + #otherwise. > + sym_data = [ > + '#undef _GNU_SOURCE', > + mode_define, > + '#define _TIME_BITS 64', > + '#define _FILE_OFFSET_BITS 64', > + '#include <stddef.h>', > + '#include <sys/stat.h>', > + 'START', > + ('sizeof_stat', 'sizeof (struct stat)'), > + ('st_dev', 'offsetof (struct stat, st_dev)'), > + ('st_ino', 'offsetof (struct stat, st_ino)'), > + ('st_mode', 'offsetof (struct stat, st_mode)'), > + ('st_nlink', 'offsetof (struct stat, st_nlink)'), > + ('st_uid', 'offsetof (struct stat, st_uid)'), > + ('st_gid', 'offsetof (struct stat, st_gid)'), > + ('st_rdev', 'offsetof (struct stat, st_rdev)'), > + ('st_size', 'offsetof (struct stat, st_size)'), > + ('st_blksize', 'offsetof (struct stat, st_blksize)'), > + ('st_blocks', 'offsetof (struct stat, st_blocks)'), > + ('st_atime', 'offsetof (struct stat, st_atime)'), > + ('st_mtime', 'offsetof (struct stat, st_mtime)'), > + ('st_ctime', 'offsetof (struct stat, st_ctime)'), > + '#ifdef __USE_XOPEN2K8', > + ('st_atimensec', 'offsetof (struct stat, st_atim.tv_nsec)'), > + ('st_mtimensec', 'offsetof (struct stat, st_mtim.tv_nsec)'), > + ('st_ctimensec', 'offsetof (struct stat, st_ctim.tv_nsec)'), > + '#else', > + ('st_atimensec', 'offsetof (struct stat, st_atimensec)'), > + ('st_mtimensec', 'offsetof (struct stat, st_mtimensec)'), > + ('st_ctimensec', 'offsetof (struct stat, st_ctimensec)'), > + '#endif', > + ] > + return glibcextract.compute_c_consts(sym_data, cc) > + > + > +def main(): > + parser = argparse.ArgumentParser( > + description='Check that feature-test macros do not change ' > + 'the time64 stat layout.') > + parser.add_argument('--cc', metavar='CC', > + help='C compiler (including options) to use') > + args = parser.parse_args() > + default_layout = compute_stat_layout(args.cc, '#define _GNU_SOURCE 1') > + status = 0 > + for mode, mode_define in sorted(MODES.items()): > + mode_layout = compute_stat_layout(args.cc, mode_define) > + for name, value in default_layout.items(): > + if mode_layout[name] != value: > + print('FAIL: %s: %s is %s, %s in default mode' > + % (mode, name, mode_layout[name], value)) > + status = 1 > + if status == 0: > + print('PASS: struct stat layout is feature-test-macro invariant') > + sys.exit(status) > + > + > +if __name__ == '__main__': > + main() > > > And this approach uncovered a similar issue on arc and ork1, which are both > 32-bit with 64-bit time_t by default. Different than riscv32, another 32-bit > with 64-bit time_t, alignof(int64) == 4 and thus 'struct stat' size and > internal layout (sigh...) differ. > > The fix would require to change de generic implementation > sysdeps/unix/sysv/linux/bits/struct_stat.h: > > iff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h > index e912c3f6ba5..cdbe1f8f762 100644 > --- a/sysdeps/unix/sysv/linux/bits/struct_stat.h > +++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h > @@ -41,6 +41,22 @@ > int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name > #endif > > +/* The pre-POSIX.1-2008 timestamp fields must match the layout of the > + 'struct timespec' members used in the POSIX.1-2008 case, including the > + padding required when the seconds field is wider than the word size. */ > +#if __WORDSIZE == 64 \ > + || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) \ > + || (__TIMESIZE == 32 && !defined __USE_TIME64_REDIRECTS) > +# define __fieldts(name) \ > + __time_t name; unsigned long int name ## nsec > +#elif __BYTE_ORDER == __BIG_ENDIAN > +# define __fieldts(name) \ > + __time_t name; int: 32; unsigned long int name ## nsec > +#else > +# define __fieldts(name) \ > + __time_t name; unsigned long int name ## nsec; int: 32 > +#endif > + > struct stat > { > __dev_t st_dev; /* Device. */ > @@ -69,12 +85,9 @@ struct stat > # define st_mtime st_mtim.tv_sec > # define st_ctime st_ctim.tv_sec > #else > - __time_t st_atime; /* Time of last access. */ > - unsigned long int st_atimensec; /* Nscecs of last access. */ > - __time_t st_mtime; /* Time of last modification. */ > - unsigned long int st_mtimensec; /* Nsecs of last modification. */ > - __time_t st_ctime; /* Time of last status change. */ > - unsigned long int st_ctimensec; /* Nsecs of last status change. */ > + __fieldts (st_atime); /* Time of last access. */ > + __fieldts (st_mtime); /* Time of last modification. */ > + __fieldts (st_ctime); /* Time of last status change. */ > #endif > int __glibc_reserved[2]; > }; > @@ -107,17 +120,16 @@ struct stat64 > struct timespec st_mtim; /* Time of last modification. */ > struct timespec st_ctim; /* Time of last status change. */ > #else > - __time_t st_atime; /* Time of last access. */ > - unsigned long int st_atimensec; /* Nscecs of last access. */ > - __time_t st_mtime; /* Time of last modification. */ > - unsigned long int st_mtimensec; /* Nsecs of last modification. */ > - __time_t st_ctime; /* Time of last status change. */ > - unsigned long int st_ctimensec; /* Nsecs of last status change. */ > + __fieldts (st_atime); /* Time of last access. */ > + __fieldts (st_mtime); /* Time of last modification. */ > + __fieldts (st_ctime); /* Time of last status change. */ > #endif > int __glibc_reserved[2]; > }; > #endif > > +#undef __fieldts > + > /* Tell code we have these members. */ > #define _STATBUF_ST_BLKSIZE > #define _STATBUF_ST_RDEV > > I am not sure if this would require a different bug, but we will need to fix > it along with BZ#34466. I squashed your proposed change with the extra one the generic and the python tests [1], this should be complete change for all ABIs. I will test on some ABIs, but it should only really affect 32 bit ABIs. Ideally this should be backported up to 2.34. [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=ecf95727a78731465b33290bc7374114ab38b63e
Hi Adhemerval, Thanks for taking this up. The squash in ecf95727a787 looks right to me: the struct_stat_time64_helper.h changes match the series (the endian include, plus dropping the two trailing reserved words), and the __fieldts macro in bits/struct_stat.h covers the arc/or1k alignment case we had not modelled. Moving the test to a glibcextract-based script is a clear improvement — it runs in cross-compilation where our io/ tests could not. One clarification: you wrote "we will need to fix it along with BZ#34466" — I assume you meant BZ#32119 (this bug). BZ#34466 is my other, unrelated patch (POSIX.1-2024 string declarations), still awaiting review. Happy to help with ABI testing: the compile-time layout models from our original analysis cover i386, arm, ppc, mips, and riscv32, and I can add arc and or1k and run the lot against the squashed change if that is useful alongside your own testing. Just say the word. Thanks, Matthias
On 05/08/26 15:45, Matthias Goergens wrote: > Hi Adhemerval, > > Thanks for taking this up. The squash in ecf95727a787 looks right to > me: the struct_stat_time64_helper.h changes match the series (the > endian include, plus dropping the two trailing reserved words), and > the __fieldts macro in bits/struct_stat.h covers the arc/or1k > alignment case we had not modelled. Moving the test to a > glibcextract-based script is a clear improvement — it runs in > cross-compilation where our io/ tests could not. > > One clarification: you wrote "we will need to fix it along with > BZ#34466" — I assume you meant BZ#32119 (this bug). BZ#34466 is my > other, unrelated patch (POSIX.1-2024 string declarations), still > awaiting review. Oops, indeed. I was reading you BZ#34466 patch and mixed up things. > > Happy to help with ABI testing: the compile-time layout models from > our original analysis cover i386, arm, ppc, mips, and riscv32, and I > can add arc and or1k and run the lot against the squashed change if > that is useful alongside your own testing. Just say the word. For such chage that involves potential kernel or glibc changes I make/check all the potential affected ABIs (essentially the one with a libc.abilist). I haven't see any issue, but I would also run some make on native builds along with qemu-system.
On 05/08/26 16:44, Adhemerval Zanella Netto wrote: > > > On 05/08/26 15:45, Matthias Goergens wrote: >> Hi Adhemerval, >> >> Thanks for taking this up. The squash in ecf95727a787 looks right to >> me: the struct_stat_time64_helper.h changes match the series (the >> endian include, plus dropping the two trailing reserved words), and >> the __fieldts macro in bits/struct_stat.h covers the arc/or1k >> alignment case we had not modelled. Moving the test to a >> glibcextract-based script is a clear improvement — it runs in >> cross-compilation where our io/ tests could not. >> >> One clarification: you wrote "we will need to fix it along with >> BZ#34466" — I assume you meant BZ#32119 (this bug). BZ#34466 is my >> other, unrelated patch (POSIX.1-2024 string declarations), still >> awaiting review. > > Oops, indeed. I was reading you BZ#34466 patch and mixed up things. And for BZ#34466, I am checking to finally implement the POSIX 2024 support on conform and track down the remaining/missing support to fully support it.
Thanks for squashing this together with the generic-header fix. I ran an independent cross-ABI compile-time layout check against your squashed commit (ecf95727a787) versus pre-fix master (d6031665). The probe includes the actual bits/struct_stat.h and bits/struct_stat_time64_helper.h from each commit and records sizeof and 16 member offsets of struct stat for _TIME_BITS=64 _FILE_OFFSET_BITS=64 in five feature modes: default (_GNU_SOURCE), POSIX.1-1996, POSIX.1-2001, POSIX.1-2008, and X/Open 600. Targets are compiled with clang --target; arc and or1k are modeled on the layout-equivalent i386 (LE, alignof(long long)==4) and powerpc (BE, alignof(long long)==8) backends since clang has no ARC/OpenRISC backend. The i386 model reproduces the sizes and offsets measured against real glibc 2.44 headers. Result: the layout is feature-mode-invariant on every target after your change. target pre-fix strict modes vs default post-fix i386 size 116 vs 108, nsec order flipped all modes identical (108) arm size 120 vs 112 all modes identical (112) powerpc size 120 vs 112 all modes identical (112) mips o32 size 120 vs 112 all modes identical (112) mipsel size 120 vs 112, nsec order flipped all modes identical (112) riscv32 already invariant all modes identical (128) arc size 116 vs 128, timestamps 12 apart all modes identical (128) or1k nsec on wrong side of padding all modes identical (128) The generic-header fix lands exactly as your commit message describes: arc is now byte-identical to riscv32 on all measured values, and or1k matches riscv32 except the nanosecond fields at +12, the correct big-endian side. The default-mode layout is unchanged on every target, so the fix only moves the strict modes onto the existing ABI. riscv32 was already invariant before the fix, consistent with your analysis. Caveats: this is a compile-time layout model, not configured cross builds, and the arc/or1k rows rest on the backend equivalence noted above. microblazeel is not covered (no clang backend); as a helper-family port without its own endian include it follows the mipsel pattern. Matthias
On 05/08/26 23:02, Matthias Goergens wrote: > Thanks for squashing this together with the generic-header fix. > > I ran an independent cross-ABI compile-time layout check against your > squashed commit (ecf95727a787) versus pre-fix master (d6031665). The > probe includes the actual bits/struct_stat.h and > bits/struct_stat_time64_helper.h from each commit and records sizeof and > 16 member offsets of struct stat for _TIME_BITS=64 > _FILE_OFFSET_BITS=64 in five feature modes: default (_GNU_SOURCE), > POSIX.1-1996, POSIX.1-2001, POSIX.1-2008, and X/Open 600. Targets are > compiled with clang --target; arc and or1k are modeled on the > layout-equivalent i386 (LE, alignof(long long)==4) and powerpc (BE, > alignof(long long)==8) backends since clang has no ARC/OpenRISC backend. > The i386 model reproduces the sizes and offsets measured against real > glibc 2.44 headers. Thanks for checking this out. You can bootstrap a cross-compiling gcc for any supported target using the script/build-many-glibcs.py. It helps such tests a lot. > > Result: the layout is feature-mode-invariant on every target after your > change. > > target pre-fix strict modes vs default post-fix > i386 size 116 vs 108, nsec order flipped all modes identical (108) > arm size 120 vs 112 all modes identical (112) > powerpc size 120 vs 112 all modes identical (112) > mips o32 size 120 vs 112 all modes identical (112) > mipsel size 120 vs 112, nsec order flipped all modes identical (112) > riscv32 already invariant all modes identical (128) > arc size 116 vs 128, timestamps 12 apart all modes identical (128) > or1k nsec on wrong side of padding all modes identical (128) > > The generic-header fix lands exactly as your commit message describes: > arc is now byte-identical to riscv32 on all measured values, and or1k > matches riscv32 except the nanosecond fields at +12, the correct > big-endian side. The default-mode layout is unchanged on every target, > so the fix only moves the strict modes onto the existing ABI. riscv32 > was already invariant before the fix, consistent with your analysis. > > Caveats: this is a compile-time layout model, not configured cross > builds, and the arc/or1k rows rest on the backend equivalence noted > above. microblazeel is not covered (no clang backend); as a > helper-family port without its own endian include it follows the mipsel > pattern. > > Matthias