[PATCH 0/1] MR8273: msvcrt: Make ioinfo for stdio fds static.
In kernel32/tests/loader.c, child_process will try to write to stdout after calling LdrShutdownProcess. LdrShutdownProcess calls DLL_PROCESS_DETACH on msvcrt, which calls msvcrt_free_io, which frees the ioinfo blocks. So to prevent use after free in this case, we keep the ioinfos for stdin/out/err static. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8273
From: Yuxuan Shui <yshui(a)codeweavers.com> In kernel32/tests/loader.c, child_process will try to write to stdout after calling LdrShutdownProcess. LdrShutdownProcess calls DLL_PROCESS_DETACH on msvcrt, which calls msvcrt_free_io, which frees the ioinfo blocks. So to prevent use after free in this case, we keep the ioinfos for stdin/out/err static. --- dlls/msvcrt/file.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 97bfc746abc..ced01937ffa 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -153,7 +153,19 @@ ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT }; * array of pointers to ioinfo arrays [32] */ ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 }; - +static ioinfo stdio_ioinfo[3]; +static RTL_CRITICAL_SECTION_DEBUG stdio_critsect_debug[3] = +{ + { 0, 0, &stdio_ioinfo[0].crit, + { &stdio_critsect_debug[0].ProcessLocksList, &stdio_critsect_debug[0].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": stdin_cs") } }, + { 0, 0, &stdio_ioinfo[1].crit, + { &stdio_critsect_debug[1].ProcessLocksList, &stdio_critsect_debug[1].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": stdout_cs") } }, + { 0, 0, &stdio_ioinfo[2].crit, + { &stdio_critsect_debug[2].ProcessLocksList, &stdio_critsect_debug[2].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": stderr_cs") } }, +}; #if _MSVCR_VER >= 80 #if _MSVCR_VER >= 140 @@ -166,14 +178,17 @@ static inline void ioinfo_set_crit_init(ioinfo *info) { } #else + +#define EF_CRIT_INIT 0x01 + static inline BOOL ioinfo_is_crit_init(ioinfo *info) { - return info->exflag & 1; + return info->exflag & EF_CRIT_INIT; } static inline void ioinfo_set_crit_init(ioinfo *info) { - info->exflag |= 1; + info->exflag |= EF_CRIT_INIT; } #endif @@ -242,6 +257,25 @@ static inline void ioinfo_set_unicode(ioinfo *info, BOOL unicode) } #endif +#if _MSVCR_VER >= 140 +static ioinfo stdio_ioinfo[3] = +{ + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[0], -1, 0, 0, 0, 0 } }, + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[1], -1, 0, 0, 0, 0 } }, + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[2], -1, 0, 0, 0, 0 } }, +}; +#else +static ioinfo stdio_ioinfo[3] = +{ + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[0], -1, 0, 0, 0, 0 }, + .exflag = EF_CRIT_INIT }, + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[1], -1, 0, 0, 0, 0 }, + .exflag = EF_CRIT_INIT }, + { .handle = INVALID_HANDLE_VALUE, .crit = { &stdio_critsect_debug[2], -1, 0, 0, 0, 0 }, + .exflag = EF_CRIT_INIT }, +}; +#endif + typedef struct { FILE file; CRITICAL_SECTION crit; @@ -394,6 +428,8 @@ static void time_to_filetime( __time64_t time, FILETIME *ft ) static inline ioinfo* get_ioinfo_nolock(int fd) { ioinfo *ret = NULL; + if(fd>=0 && fd<3) + return &stdio_ioinfo[fd]; if(fd>=0 && fd<MSVCRT_MAX_FILES) ret = MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE]; if(!ret) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8273
Judging from the test failures in msvcrt, this probably isn't right. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8273#note_106121
There shouldn't be any need to free memory on process exit, all we need is to flush pending buffers. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8273#note_106125
On Wed Jun 11 14:22:09 2025 +0000, Alexandre Julliard wrote:
There shouldn't be any need to free memory on process exit, all we need is to flush pending buffers. Opened !8288, hope I understood what you meant correctly
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/8273#note_106241
This merge request was closed by Yuxuan Shui. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8273
participants (3)
-
Alexandre Julliard (@julliard) -
Yuxuan Shui -
Yuxuan Shui (@yshui)