On Thu, 18 Dec 2025, Pali Rohár wrote:
msvcrt _fstat function is broken and for directory fd it returns S_ISREG
type. 32-bit pre-msvcr110 _fstat does not properly signal size overflow.
UCRT seems to work correctly.
Add mingw-w64 fstat wrappers around msvcrt _fstat functions which change
S_IFMT to S_IFDIR if winapi filehandle has FILE_ATTRIBUTE_DIRECTORY
attribute set. Provide wrapper for all 4 fstat size_t/time_t variants.
For 32-bit pre-msvcr110 builds, adds similar workaround like for existing
mingw-w64 stat functions.
---
mingw-w64-crt/Makefile.am | 10 +++-
mingw-w64-crt/def-include/crt-aliases.def.in | 18 +++----
.../api-ms-win-crt-filesystem-l1-1-0.def.in | 3 ++
mingw-w64-crt/lib-common/msvcrt.def.in | 4 --
mingw-w64-crt/misc/crtdll_fstat.c | 5 --
.../stdio/__mingw_fix_fstat_finish.c | 18 +++++++
mingw-w64-crt/stdio/__mingw_fix_stat.h | 7 +++
mingw-w64-crt/stdio/_fstat64.c | 3 --
mingw-w64-crt/stdio/fstat32i64.c | 16 ++++++
mingw-w64-crt/stdio/fstat64.c | 15 ++++++
mingw-w64-crt/stdio/msvcr110plus_fstat32.c | 24 +++++++++
mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c | 24 +++++++++
mingw-w64-crt/stdio/msvcr110pre_fstat32.c | 50 +++++++++++++++++++
mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c | 50 +++++++++++++++++++
mingw-w64-crt/testcases/t_fstat.c | 49 ++++++++++++++++--
mingw-w64-headers/crt/sys/stat.h | 8 +--
16 files changed, 272 insertions(+), 32 deletions(-)
create mode 100644 mingw-w64-crt/stdio/__mingw_fix_fstat_finish.c
create mode 100644 mingw-w64-crt/stdio/fstat32i64.c
create mode 100644 mingw-w64-crt/stdio/fstat64.c
create mode 100644 mingw-w64-crt/stdio/msvcr110plus_fstat32.c
create mode 100644 mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c
create mode 100644 mingw-w64-crt/stdio/msvcr110pre_fstat32.c
create mode 100644 mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c
The added test is flaky in the CI environment. In one case, I got the
following error:
FAIL: t_fstat_t64
=================
Assertion failed: CreateDirectoryA(path, NULL), file
../../testcases/t_fstat.c, line 33
fstat(0): mode = 00010000
fstat64(0): mode = 00010000
CreateDirectoryA: path=D:\a\_temp\msys64\tmp\mingw-w64-fstat-test-2
FAIL t_fstat_t64.exe (exit status: 3)
In addition to that, it feels like there happens a bit too much at the
same time in the same patch here, is it possible to split this up into
smaller steps?
In particular:
@@ -305,23 +303,23 @@ fsetpos64 == fsetpos
lseek64 == _lseeki64
#endif
#ifdef UCRTBASE
+fstat32 == _fstat32
+fstat32i64 == _fstat32i64
+fstat64 == _fstat64
+fstat64i32 == _fstat64i32
This feels like a separate change to the rest? Before this, there was no
"fstat32" symbol in the ucrt import library, and now there is one - and
this does not fall under the scope of change that the commit message
describes.
diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat.h
b/mingw-w64-crt/stdio/__mingw_fix_stat.h
index 909606204b4d..1317dbffe2e8 100644
--- a/mingw-w64-crt/stdio/__mingw_fix_stat.h
+++ b/mingw-w64-crt/stdio/__mingw_fix_stat.h
@@ -11,5 +11,12 @@ char* __mingw_fix_stat_path (const char* _path);
wchar_t* __mingw_fix_wstat_path (const wchar_t* _path);
int __mingw_fix_stat_finish(int ret, const void *orig_path, void *used_path,
unsigned short mode);
+int __mingw_fix_fstat_finish(int ret, int fd, unsigned short *mode);
+
+#define __MINGW_FIXED_FSTAT(fstat_func, fd, obj) ({ \
+ int _fstat_ret = fstat_func(fd, obj); \
+ _fstat_ret = __mingw_fix_fstat_finish(_fstat_ret, fd, &(obj)->st_mode); \
+ _fstat_ret; \
+})
What is this construct? Is this the GCC extension for statement
expression?
Our supported compilers do accept it, but can we avoid using it if we
could?
// Martin
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public