On 2025-02-25 Pali Rohár wrote: > On Tuesday 25 February 2025 20:11:12 Lasse Collin wrote: > > MSVCRT's _stat() fails with "directory/", but in POSIX a trailing > > slash should work for directories (and only for directories). > > mingw-w64-crt/stdio/_stat.c provides stat() that, with some > > exceptions, removes *one* trailing / or \ and then calls _stat(). > > This hack is often enough, but as a side effect it then makes > > "file/" succeed while it shouldn't. And "directory//" still fails > > while it shouldn't. > > > > On UCRT, stat() simply calls _stat(). UCRT's _stat() has eerily > > similar behavior with trailing slashes as mingw-w64's replacement > > stat() has in MSVCRT builds. It's as if UCRT was made bug-for-bug > > compatible with mingw-w64 instead of thinking what is the correct > > but more complex thing to do. > > > > MSVCRT's _stat() doesn't work on \\.\ or \\?\ paths. UCRT's does, > > but the buggy trailing slash removal means that only the last line > > below succeeds with UCRT's _stat(): > > > > \\?\GLOBALROOT\Device\Harddisk0\Partition3 > > \\?\GLOBALROOT\Device\Harddisk0\Partition3\ > > \\?\GLOBALROOT\Device\Harddisk0\Partition3\\ > > > > MSVCRT's _stat() doesn't follow reparse points. UCRT's _stat() does > > (on symlink or junction loops it fails with ENOENT, not ELOOP). > > MS _stat() function can do whatever it wants. It is not part of C or > POSIX.
I agree. > But mingw-w64's stat() function should be consistent and returns > correct information. What you have figured out is another mess. It is > not nice. I apologize what I said about UCRT's _stat. It's fine. :-) It doesn't emulate any mingw-w64 bugs, and making stat == _stat is OK with UCRT. It's mingw-w64 that is broken. I had tested on MSYS2 in MINGW32 and UCRT64 environments. In the MINGW32 environment, _USE_32BIT_TIME_T is defined by default while in UCRT64 it's not defined. Earlier I had built a stat/_stat testing program with optimizations disabled. Building with optimizations enabled (-O2), the UCRT results changed for both _stat and stat. Now trailing slashes work the way they should. <sys/stat.h> provides __CRT_INLINE ("extern inline __attribute__((__gnu_inline__))") wrapper for these functions: _fstat64i32 _stat64i32 fstat (two versions depending on _USE_32BIT_TIME_T) There are also two versions of stat but they have been commented out: /* Disable it for making sure trailing slash issue is fixed. */ The above inline functions are provided only when optimizations are enabled. Even in optimized builds, compiler may decide to not use the inline functions and instead may emit calls to the external functions. It's essential that the inline implementation in the header and the implementation in libmingwex have the same behavior. They are the same for _fstat64i32. _stat64i32 has a bug: The inline function doesn't remove a trailing slash but mingw-w64-crt/stdio/_stat64i32.c does. Thus the behavior of the function depends on compiler optimizations. In MSYS2's MINGW32 environment, stat is defined to _stat32, so calling _stat jumps into MSVCRT without any libmingwex code. A call to stat goes to libmingwex's wrapper that removes one trailing slash. In this case everything works the way I think it's intended to work. In the UCRT64 environment, _stat is defined to _stat64i32 in <_mingw_stat64.h>. UCRT builds of libmingwex include mingw-w64-crt/stdio/_stat64i32.c. This is wrong because UCRT's functions handle trailing slashes (MSVCRT's don't). This explains why I thought that UCRT had imitated mingw-w64's slash removal. Compiling with optimizations enabled made the compiler use the __CRT_INLINE version from <sys/stat.h>, skipping the slash removal version from libmingwex. For UCRT builds, <sys/stat.h> uses __mingw_ovr to make stat an alias for _stat. Thus stat and _stat behave the same. fstat __CRT_INLINE usage I didn't investigate much. At glance it looks suspicious because the definition of "struct stat" depends on time_t but there's only one non-inline fallback function. c0f06309823c ("crt: Provide fstat function symbol via alias") removed _fstat.c with a time_t related FIXME but left the inline functions in <sys/stat.h>. As the FIXME said, the old method was known to be incorrect. The same FIXME is in _stat.c and _wstat.c still, but due to the __mingw_ovr in <sys/stat.h> in UCRT builds, I suspect that the code from _stat.c and _wstat.c is never called in UCRT builds. Thus the time_t FIXME in these two files only matters to MSVCRT builds. (I don't know if Autoconf detection of stat and wstat still needs a symbol in libmingwex because AC_CHECK_FUNC doesn't look at headers.) -- Lasse Collin _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public