On Saturday 29 March 2025 12:19:19 Lasse Collin wrote: > On 2025-03-28 Pali Rohár wrote: > > On Saturday 22 March 2025 15:35:48 Lasse Collin wrote: > > > I verified in MSYS2's CLANG64 environment that -fsanitize=function > > > and -fsanitize=undefined do complain on Windows too. > > > > > > file1.c: > > > > > > struct foo { int x; }; > > > int foo(struct foo *f); > > > > > > int main(void) > > > { > > > struct foo f = { 5 }; > > > int (*cb)(struct foo *f) = &foo; > > > return cb(&f); > > > } > > > > > > file2.c: > > > > > > struct wrongname { int x; }; > > > > > > int foo(struct wrongname *f) > > > { > > > return f->x; > > > } > > > > > > Testing: > > > > > > $ clang -O2 -fsanitize=undefined file1.c file2.c > > > $ ./a > > > file1.c:8:12: runtime error: call to function foo through pointer > > > to incorrect function type 'int (*)(struct foo *)' > > > (C:\msys64\home\....): note: foo defined here SUMMARY: > > > UndefinedBehaviorSanitizer: undefined-behavior file1.c:8:12 > > > > > > If I build with "clang -O2 -fsanitize=cfi -flto" then the program > > > terminates with an illegal instruction instead. > > > > Ah, that is bad :-( Is not there some attribute to mark the function > > to add either structure name alias or turn off the runtime check for > > particular function? > > I tried __attribute__((no_sanitize("cfi"))) and a few related > attributes. These work if used in the calling code, for example, on the > main() function in the above example. They don't help if applied to the > foo() declaration or definition. That is, the attributes don't seem > helpful here. Even if an attribute worked, it would poke a small hole > in the CFI protection.
Would it help if we compile stat*.c mingw-w64 source files with -fno-lto option? Or this also does not work? > Clang supports -fsanitize-ignorelist=filename.txt. With a very quick > try, it worked for -fsanitize=undefined but not for =cfi. But even if > it worked, this wouldn't really feel like a real solution. > > https://clang.llvm.org/docs/SanitizerSpecialCaseList.html > > The sanitizer issue should be easy enough to fix properly. Each stat*.c > would, if needed, define _USE_32BIT_TIME_T and _FILE_OFFSET_BITS, and > then use "struct stat". That is, a similar method as my ftw patch used. Problem is that you cannot define _USE_32BIT_TIME_T on UCRT builds. There are header ifdef checks that combination of _USE_32BIT_TIME_T and _UCRT throw preprocessor #error. But UCRT has _stat32 and also _stat32i64 functions. So this would not work. > -int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) > +int __cdecl stat64i32(const char *_Filename, struct stat *_Stat) > { > char *_path = __mingw_fix_stat_path(_Filename); > if (_path == NULL) > return -1; > - int ret = _stat64i32(_path, _Stat); > + int ret = _stat64i32(_path, (struct _stat64i32 *)_Stat); > > Adding the cast doesn't create a new strict aliasing issue; it only > makes the existing strict aliasing issue easier to see. So the above > idea fixes the -fsanitize problem but doesn't make the strict aliasing > situation better or worse. (I'm not sure right now if attributes can > help with that in this specific situation.) Strict aliasing issue on particular type could be probably fixed by the __attribute__((__may_alias__)). > There would also need to be fifth stat*.c file to provide a stat64() > function that uses "struct stat64". Other than the argument type, it > would be ABI compatible with regular stat64(). Assuming that -fsanitize > isn't a worry when directly calling MS CRT functions, only non-UCRT > builds would need the fifth stat*.c file. > > #ifdef _UCRT > // stat64 is redirected in the .def file. > int __cdecl stat64(const char *_Filename, struct stat64 *_Stat); > #else > // Wrapper that converts the argument type to keep -fsanitize=function > // and -fsanitize=cfi happy. > int __cdecl stat64(const char *_Filename, struct stat64 *_Stat) > __MINGW_ASM_CALL(__mingw_lfs_stat64); > #endif This is for sure wrong. UCRT and msvcrt has same ABI for stat* functions. So any such ifdef looks very suspicious. Why two libraries with same ABI requires differences in the header? > > > OK, sorry. I had thought that the misuse of __CRT__NO_INLINE in > > > <sys/stat.h> was a somewhat severe bug, and fixing it as a side > > > effect could have been easy enough here. > > > > As other people pointed out, this needs to be fixed. I proposed one > > solution in other thread. > > > > > In <ftw.h> I used __CRT_BUILDING_FTW. It can be renamed, of course. > > > A separate macro for <ftw.h> is convenient because building ftw*.c > > > depends on the seeing the correct stat struct and function from > > > <sys/stat.h>. > > > > I'm proposing alternative solution to this ftw problem, without > > introduction of any new macro. What do you think about it? > > > > It is attached in ftw.patch file. > > I suspect it doesn't work if we care about -fsanitize. The problem > is the callback function provided by the application. It takes a > pointer to struct stat, but with your patch the struct name is not > "stat". > > On the other hand, -fsanitize with ftw() (but not nftw()) is already > broken because do_it() always calls the callback function with four > arguments. It's easy, if slightly ugly, to fix by adding another > function pointer to struct ctx_t, and then picking the right one with a > helper function. > > If the above aren't a concern, your patch seems fine to me. :-) However, > I'm not sure what else it truly fixes than the ABI symbol names and > avoids new macros in the public headers. If my idea (2) from the other > thread was used, the beginning of ftw.c could have > > #define __MINGW_CRTBLD_STAT_VISIBLE > > and <ftw.h> could hide the declarations behind _CRTBLD. So > __CRT_BUILDING_FTW wouldn't be needed. The only new macro would be > __MINGW_CRTBLD_STAT_VISIBLE. > > > Also it fixes the ABI problem which you have there. In both 32-bit > > msvcrt and 32-bit UCRT builds is "stat" symbol ABI compatible with > > stat32. Even the fact that 32-bit UCRT uses stat function API > > compatible with stat64i32. So it is needed to distinguish between ABI > > symbols and API functions. In your original change you used 32-bit > > UCRT ftw symbol compatible with ftw64i32, which breaks API/ABI > > compatibility with stat symbol and struct stat. > > Thanks! I should have copied the #ifdefs from your stat*.c files. > > -- > Lasse Collin _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public