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

Reply via email to