From: Shengdun Wang unlvsur@live.com
UCRT's FILE struct and fd struct have different layouts and their locks are different. Implementation in Wine does not match UCRT in windows, causing ABI issues.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53960 --- dlls/msvcrt/file.c | 30 ++++++++++++++----- dlls/msvcrt/msvcrt.h | 10 +++++-- dlls/msvcrt/tests/file.c | 53 +++++++++++++++++++++++++++++++++ include/msvcrt/corecrt_wstdio.h | 5 ++++ include/msvcrt/stdio.h | 21 +++++++++++++ 5 files changed, 110 insertions(+), 9 deletions(-)
diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 24cca6fb63e..bbd395c725c 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -246,7 +246,11 @@ typedef struct { CRITICAL_SECTION crit; } file_crit;
+#ifdef _UCRT +static file_crit MSVCRT__iob[_IOB_ENTRIES] = { { { 0 } } }; +#else FILE MSVCRT__iob[_IOB_ENTRIES] = { { 0 } }; +#endif static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE]; static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
@@ -502,7 +506,7 @@ static inline FILE* msvcrt_get_file(int i) return NULL;
if(i < _IOB_ENTRIES) - return &MSVCRT__iob[i]; + return (FILE*)&MSVCRT__iob[i];
ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]; if(!ret) { @@ -604,7 +608,9 @@ static FILE* msvcrt_alloc_fp(void) { if (i == MSVCRT_stream_idx) { +#ifndef _UCRT if (file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES) +#endif { InitializeCriticalSectionEx(&((file_crit*)file)->crit, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); ((file_crit*)file)->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_crit.crit"); @@ -784,14 +790,18 @@ void msvcrt_init_io(void) get_ioinfo_nolock(STDOUT_FILENO)->handle, get_ioinfo_nolock(STDERR_FILENO)->handle);
- memset(MSVCRT__iob,0,3*sizeof(FILE)); + memset(MSVCRT__iob,0,3*sizeof(*MSVCRT__iob)); for (i = 0; i < 3; i++) { /* FILE structs for stdin/out/err are static and never deleted */ - MSVCRT__iob[i]._file = get_ioinfo_nolock(i)->handle == MSVCRT_NO_CONSOLE ? + ((FILE*)(MSVCRT__iob+i))->_file = get_ioinfo_nolock(i)->handle == MSVCRT_NO_CONSOLE ? MSVCRT_NO_CONSOLE_FD : i; - MSVCRT__iob[i]._tmpfname = NULL; - MSVCRT__iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT; + ((FILE*)(MSVCRT__iob+i))->_tmpfname = NULL; + ((FILE*)(MSVCRT__iob+i))->_flag = (i == 0) ? _IOREAD : _IOWRT; +#ifdef _UCRT + InitializeCriticalSectionEx(&MSVCRT__iob[i].crit, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); + MSVCRT__iob[i].crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_crit.crit"); +#endif } MSVCRT_stream_idx = 3; } @@ -936,7 +946,7 @@ static int msvcrt_int_to_base32_w(int num, wchar_t *str) #undef __iob_func FILE * CDECL __iob_func(void) { - return &MSVCRT__iob[0]; + return (FILE*)(&MSVCRT__iob[0]); }
#if _MSVCR_VER >= 140 @@ -945,7 +955,7 @@ FILE * CDECL __iob_func(void) */ FILE * CDECL __acrt_iob_func(unsigned idx) { - return &MSVCRT__iob[idx]; + return (FILE*)(&MSVCRT__iob[idx]); } #endif
@@ -1390,7 +1400,9 @@ void msvcrt_free_io(void) for(j=0; j<MSVCRT_stream_idx; j++) { FILE *file = msvcrt_get_file(j); +#ifndef _UCRT if(file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES) +#endif { ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&((file_crit*)file)->crit); @@ -1461,9 +1473,11 @@ __msvcrt_long CDECL _lseek(int fd, __msvcrt_long offset, int whence) */ void CDECL _lock_file(FILE *file) { +#ifndef _UCRT if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES) _lock(_STREAM_LOCKS+(file-MSVCRT__iob)); else +#endif EnterCriticalSection(&((file_crit*)file)->crit); }
@@ -1472,9 +1486,11 @@ void CDECL _lock_file(FILE *file) */ void CDECL _unlock_file(FILE *file) { +#ifndef _UCRT if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES) _unlock(_STREAM_LOCKS+(file-MSVCRT__iob)); else +#endif LeaveCriticalSection(&((file_crit*)file)->crit); }
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index dd7fb5895a0..9014c7d3ff9 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -284,14 +284,20 @@ extern BOOL msvcrt_create_io_inherit_block(WORD*, BYTE**); #define _RT_CRNL 252 #define _RT_BANNER 255
-extern FILE MSVCRT__iob[]; - #define MSVCRT_NO_CONSOLE_FD (-2) #define MSVCRT_NO_CONSOLE ((HANDLE)MSVCRT_NO_CONSOLE_FD)
+#ifdef _UCRT +#define MSVCRT_stdin stdin +#define MSVCRT_stdout stdout +#define MSVCRT_stderr stderr +#else +extern FILE MSVCRT__iob[]; + #define MSVCRT_stdin (MSVCRT__iob+STDIN_FILENO) #define MSVCRT_stdout (MSVCRT__iob+STDOUT_FILENO) #define MSVCRT_stderr (MSVCRT__iob+STDERR_FILENO) +#endif
/* internal file._flag flags */ #define MSVCRT__USERBUF 0x0100 diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index b81469009cd..b90030caf22 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -3123,6 +3123,58 @@ static void test_std_stream_buffering(void) ok(DeleteFileA("std_stream_test.tmp"), "DeleteFile failed\n"); }
+struct test_iobuf +{ + char* _ptr; +#ifdef _UCRT + char* _base; + int _cnt; +#else + int _cnt; + char* _base; +#endif + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char* _tmpfname; +}; + +static void test_iobuf_layout(void) +{ + ok(offsetof(FILE, _base)==offsetof(struct test_iobuf, _base) && + offsetof(FILE, _cnt)==offsetof(struct test_iobuf, _cnt), "FILE layout incorrect"); +#ifdef _UCRT + ok(stdout!=stdin+1, "ucrt stdout FILE must not be adject to stdin"); + ok(_IOBUFFER_CRT == 0x0040 && _IOBUFFER_CRT == _IOMYBUF, "UCRT _IOBUFFER_CRT should be 0x0040"); +#else + ok(stdout==stdin+1, "msvcrt stdout FILE must be adject to stdin"); + ok(_IOMYBUF == 0x0008, "MSVCRT _IOBUFFER_CRT should be 0x0008"); +#endif + + char *tempf; + FILE *file; + char *bufptrold; + int cntold; + + tempf = _tempnam(".","wne"); + file = fopen(tempf, "wb"); + + fprintf(file, "Hello World\n"); + bufptrold = file->_base; + cntold = file->_cnt; + if (bufptrold && cntold) + { + fprintf(file, "Hello"); + ok(bufptrold + 5 == file->_base, "FILE _base ptr incorrect updated"); + ok(cntold - 5 == file->_cnt, "FILE _cnt incorrect updated"); + ok(bufptrold + cntold == file->_base + file->_cnt, "FILE _base ptr or _cnt incorrect updated"); + ok(file->_flag&_IOMYBUF == _IOMYBUF, "file->_flag's _IOBUFFER_CRT updated incorrectly"); + } + fclose(file); + unlink(tempf); +} + START_TEST(file) { int arg_c; @@ -3200,6 +3252,7 @@ START_TEST(file) test_open_hints(); test_ioinfo_flags(); test_std_stream_buffering(); + test_iobuf_layout();
/* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order diff --git a/include/msvcrt/corecrt_wstdio.h b/include/msvcrt/corecrt_wstdio.h index 404f7345c8e..30caf56e6ef 100644 --- a/include/msvcrt/corecrt_wstdio.h +++ b/include/msvcrt/corecrt_wstdio.h @@ -26,8 +26,13 @@ extern "C" { typedef struct _iobuf { char* _ptr; +#ifdef _UCRT + char* _base; + int _cnt; +#else int _cnt; char* _base; +#endif int _flag; int _file; int _charbuf; diff --git a/include/msvcrt/stdio.h b/include/msvcrt/stdio.h index 745257ea5cc..9c82a3b6a5a 100644 --- a/include/msvcrt/stdio.h +++ b/include/msvcrt/stdio.h @@ -11,6 +11,26 @@ #include <corecrt_wstdio.h>
/* file._flag flags */ +#if defined(_UCRT) +#define _IOREAD 0x0001 +#define _IOWRITE 0x0002 +#define _IOWRT _IOWRITE +#define _IOUPDATE 0x0004 +#define _IORW _IOUPDATE +#define _IOEOF 0x0008 +#define _IOERR 0x0010 +#define _IOCTRLZ 0x0020 +#define _IOBUFFER_CRT 0x0040 +#define _IOMYBUF _IOBUFFER_CRT +#define _IOBUFFER_USER 0x0080 +#define _IOBUFFER_SETVBUF 0x0100 +#define _IOBUFFER_STBUF 0x0200 +#define _IOBUFFER_NONE 0x0400 +#define _IOCOMMIT 0x0800 +#define _IOSTRING 0x1000 +#define _IOSTRG _IOSTRING +#define _IOALLOCATED 0x2000 +#else #define _IOREAD 0x0001 #define _IOWRT 0x0002 #define _IOMYBUF 0x0008 @@ -18,6 +38,7 @@ #define _IOERR 0x0020 #define _IOSTRG 0x0040 #define _IORW 0x0080 +#endif
#define STDIN_FILENO 0 #define STDOUT_FILENO 1