https://bugs.winehq.org/show_bug.cgi?id=50409
Bug ID: 50409 Summary: Adobe Audition 2020 crashes on startup (msvcrt strftime_impl uses __lc_time_data struct WCHAR members but only ANSI members have been initialized by _Gettnames) Product: Wine Version: 6.0-rc4 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: msvcrt Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
continuation of bug 50401 ("Multiple Adobe products crash on unimplemented function msvcp{100,110,120,140}.dll._Wcsxfrm (Audition CS6, Audition 2020)").
After providing a simple implementation it crashes:
--- snip --- $ WINEDEBUG=+seh,+relay,+msvcrt,+msvcp wine ./Adobe\ Audition.exe >>log.txt 2>&1 ... 0104:Call PE DLL (proc=0000000000B0D040,module=0000000000A90000 L"MSVCP140.dll",reason=PROCESS_ATTACH,res=000000000021FB00) 0104:trace:msvcp:DllMain (0x0000000000A90000, 1, 000000000021FB00) ... 0104:Call KERNEL32.CreateFileW(142a9c00 L"\\?\C:\users\focht\Application Data\Adobe\Audition\13.0\logs\Audition Log.txt",c0000000,00000001,0021eec0,00000003,00000080,00000000) ret=1800cb243 ... 0104:Ret KERNEL32.CreateFileW() retval=000000fc ret=1800cb243 ... 0104:Call ucrtbase._Gettnames() ret=00ae7e6d 0104:trace:msvcrt:_Gettnames 0104:Call ntdll.RtlAllocateHeap(13f60000,00000000,000003d1) ret=00335a9e 0104:Ret ntdll.RtlAllocateHeap() retval=13f897a0 ret=00335a9e 0104:Ret ucrtbase._Gettnames() retval=13f897a0 ret=00ae7e6d 0104:trace:msvcp:_Timevec_ctor_timeptr (0000000013F89780 0000000013F897A0) 0104:trace:msvcp:locale_id_operator_size_t (0000000000B49908) 0104:trace:msvcp:locale__Locimp__Locimp_Addfac (0000000013F87280 0000000013F89770 7) 0104:trace:msvcp:locale_facet__Incref (0000000013F89770) 0104:trace:msvcp:codecvt_char__Getcat (0000000000000000 0000000000000000) ... 0104:trace:msvcp:time_put_char_put_format (0000000013F89770 000000000021ED98 000000000021ED28 000000000021EDC8 "%c") 0104:trace:msvcp:time_put_char_put (0000000013F89770 000000000021EC60 000000000021ED28 000000000021EDC8 c (0000000013F89770 000000000021EC60 000000000021ED28 000000000021EDC8 c Call ucrtbase._Strftime(0021ea20,00000040,0021ea1c "%c",0021edc8,13f897a0) ret=00ae84b4 0104:trace:msvcrt:strftime_helper (000000000021EA20 64 %c 000000000021EDC8 0000000013F897A0 0000000000000000) 0104:Call ntdll.RtlAllocateHeap(13f60000,00000000,00000006) ret=00335a9e 0104:Ret ntdll.RtlAllocateHeap() retval=1404e270 ret=00335a9e 0104:Call ntdll.RtlAllocateHeap(13f60000,00000000,00000080) ret=00335a9e 0104:Ret ntdll.RtlAllocateHeap() retval=1404e2a0 ret=00335a9e 0104:Call KERNEL32.HeapFree(13f60000,00000000,1404e2a0) ret=00335a30 0104:Ret KERNEL32.HeapFree() retval=0021ed01 ret=00335a30 0104:Call KERNEL32.HeapFree(13f60000,00000000,1404e270) ret=00335a30 0104:Ret KERNEL32.HeapFree() retval=0021ed01 ret=00335a30 0104:Ret ucrtbase._Strftime() retval=ffffffffffffffff ret=00ae84b4 0104:trace:msvcp:basic_streambuf_char_sputc (000000000021ECA8 0) 0104:trace:msvcp:basic_streambuf_char__Pnavail (000000000021ECA8) 0104:Call msvcp140.?pptr@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IEBAPEADXZ(0021eca8) ret=180040fdc 0104:trace:msvcp:basic_streambuf_char_pptr (000000000021ECA8) 0104:Ret msvcp140.?pptr@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IEBAPEADXZ() retval=00000000 ret=180040fdc 0104:Call ucrtbase.malloc(00000020) ret=180242c1f 0104:Call ntdll.RtlAllocateHeap(13f60000,00000000,00000020) ret=00335a9e 0104:Ret ntdll.RtlAllocateHeap() retval=1404e270 ret=00335a9e 0104:Ret ucrtbase.malloc() retval=1404e270 ret=180242c1f 0104:Call ucrtbase.memcpy(1404e270,00000000,00000000) ret=180041086 0104:Ret ucrtbase.memcpy() retval=1404e270 ret=180041086 0104:Call msvcp140.?_Pninc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IEAAPEADXZ(0021eca8) ret=180041127 0104:trace:msvcp:basic_streambuf_char__Pninc (000000000021ECA8) 0104:Ret msvcp140.?_Pninc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IEAAPEADXZ() retval=1404e270 ret=180041127 0104:trace:msvcp:basic_streambuf_char_sputc (000000000021ECA8 -21) 0104:trace:msvcp:basic_streambuf_char__Pnavail (000000000021ECA8) ... 0104:trace:msvcp:basic_streambuf_char__Pninc (000000000021ECA8) 0104:trace:msvcp:basic_streambuf_char_sputc (000000000021ECA8 0) 0104:trace:msvcp:basic_streambuf_char__Pnavail (000000000021ECA8) 0104:trace:msvcp:basic_streambuf_char__Pninc (000000000021ECA8) 0104:trace:seh:dispatch_exception code=c0000005 flags=0 addr=0000000000AE84D1 ip=0000000000AE84D1 tid=0104 0104:trace:seh:dispatch_exception info[0]=0000000000000000 0104:trace:seh:dispatch_exception info[1]=0000000000289000 0104:trace:seh:dispatch_exception rax=0000000000000000 rbx=00000000ffffffff rcx=0000000014dda61f rdx=0000000014dda620 0104:trace:seh:dispatch_exception rsi=000000000021ec60 rdi=000000000021eb20 rbp=000000000006a5e0 rsp=000000000021e9c0 0104:trace:seh:dispatch_exception r8=00000000000fffff r9=000000000021e538 r10=000000000021e101 r11=0000000000000246 0104:trace:seh:dispatch_exception r12=000000000021edaa r13=000000000021edc8 r14=000000000021edc8 r15=0000000000000000 0104:trace:seh:call_vectored_handlers calling handler at 000000007B011BA0 code=c0000005 flags=0 0104:trace:seh:call_vectored_handlers handler at 000000007B011BA0 returned 0 0104:trace:seh:RtlVirtualUnwind type 1 rip 0000000000AE84D1 rsp 000000000021E9C0 0104:trace:seh:dump_unwind_info **** func 583f0-584ff 0104:trace:seh:dump_unwind_info unwind info at 0000000000B3D628 flags 0 prolog 0xf bytes function 0000000000AE83F0-0000000000AE84FF --- snip ---
Application _MSVCR_VER = 140
_Strftime() failing for '%c' seemed strange.
https://source.winehq.org/git/wine.git/blob/e377786a71c3b6eab5bc11c0b1c9c7c3...
--- snip --- 1081 static size_t strftime_impl(STRFTIME_CHAR *str, size_t max, 1082 const STRFTIME_CHAR *format, const struct tm *mstm, 1083 __lc_time_data *time_data, _locale_t loc) 1084 { 1085 size_t ret, tmp; 1086 BOOL alternate; 1087 int year = mstm ? mstm->tm_year + 1900 : -1; 1088 1089 if(!str || !format) { 1090 if(str && max) 1091 *str = 0; 1092 *_errno() = EINVAL; 1093 return 0; 1094 } 1095 1096 if(!time_data) 1097 time_data = loc ? loc->locinfo->lc_time_curr : get_locinfo()->lc_time_curr; 1098 1099 for(ret=0; *format && ret<max; format++) { 1100 if(*format != '%') { 1101 if(_isleadbyte_l((unsigned char)*format, loc)) { 1102 str[ret++] = *(format++); 1103 if(ret == max) continue; 1104 if(!MSVCRT_CHECK_PMT(str[ret])) 1105 goto einval_error; 1106 } 1107 str[ret++] = *format; 1108 continue; 1109 } 1110 1111 format++; 1112 if(*format == '#') { 1113 alternate = TRUE; 1114 format++; 1115 }else { 1116 alternate = FALSE; 1117 } 1118 1119 if(!MSVCRT_CHECK_PMT(mstm)) 1120 goto einval_error; 1121 1122 switch(*format) { 1123 case 'c': 1124 #if _MSVCR_VER>=140 1125 if(time_data == &cloc_time_data && !alternate) 1126 { 1127 tmp = strftime_impl(str+ret, max-ret, L"%a %b %e %T %Y", mstm, time_data, loc); 1128 if(!tmp) 1129 return 0; 1130 ret += tmp; 1131 break; 1132 } 1133 #endif 1134 if(!strftime_format(str, &ret, max, mstm, time_data, 1135 alternate ? STRFTIME_TD(time_data, date) : STRFTIME_TD(time_data, short_date))) 1136 return 0; 1137 if(ret < max) 1138 str[ret++] = ' '; 1139 if(!strftime_format(str, &ret, max, mstm, time_data, STRFTIME_TD(time_data, time))) 1140 return 0; 1141 break; ... 1416 if(ret == max) { 1417 if(max) 1418 *str = 0; 1419 *_errno() = ERANGE; 1420 return 0; 1421 } 1422 1423 str[ret] = 0; 1424 return ret; 1425 1426 einval_error: 1427 *str = 0; 1428 return 0; 1429 } --- snip ---
_MSVCR_VER >= 140 case.
'strftime_format( ... STRFTIME_TD(time_data, short_date))' failed while 'strftime_format( ... STRFTIME_TD(time_data, time)))' partially worked (by chance), leading to output buffer content:
--- snip --- 01404E290 00 00 00 00 00 00 00 00 88 00 00 00 55 53 45 08 ............USE. 01404E2A0 20 00 31 00 32 00 3A 00 33 00 33 00 3A 00 30 00 .1.2.:.3.3.:.0. 01404E2B0 30 00 20 00 41 64 74 80 92 F8 13 00 00 00 00 00 0. .Adt..ΓΈ...... 01404E2C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01404E2D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ --- snip ---
str = " 12:33:00 " = 10 wchars, rest is garbage (uninit). ret = 0xe -> str[0xe] = null terminate behind garbage
'strftime_format( .. STRFTIME_TD(time_data, short_date))' fails due to 'time_data->shortdate' being a NULL string.
https://source.winehq.org/git/wine.git/blob/e377786a71c3b6eab5bc11c0b1c9c7c3...
--- snip --- 47 typedef struct __lc_time_data { 48 union { 49 const char *str[43]; 50 struct { 51 const char *short_wday[7]; 52 const char *wday[7]; 53 const char *short_mon[12]; 54 const char *mon[12]; 55 const char *am; 56 const char *pm; 57 const char *short_date; 58 const char *date; 59 const char *time; 60 } names; 61 } str; 62 #if _MSVCR_VER < 110 63 LCID lcid; 64 #endif 65 int unk; 66 int refcount; 67 union { 68 const wchar_t *wstr[43]; 69 struct { 70 const wchar_t *short_wday[7]; 71 const wchar_t *wday[7]; 72 const wchar_t *short_mon[12]; 73 const wchar_t *mon[12]; 74 const wchar_t *am; 75 const wchar_t *pm; 76 const wchar_t *short_date; 77 const wchar_t *date; 78 const wchar_t *time; 79 } names; 80 } wstr; 81 #if _MSVCR_VER >= 110 82 const wchar_t *locname; 83 #endif 84 char data[1]; 85 } __lc_time_data; --- snip ---
The log again:
--- snip --- 0104:Call ucrtbase._Gettnames() ret=00ae7e6d 0104:trace:msvcrt:_Gettnames 0104:Call ntdll.RtlAllocateHeap(13f60000,00000000,000003d1) ret=00335a9e 0104:Ret ntdll.RtlAllocateHeap() retval=13f897a0 ret=00335a9e 0104:Ret ucrtbase._Gettnames() retval=13f897a0 ret=00ae7e6d 0104:trace:msvcp:_Timevec_ctor_timeptr (0000000013F89780 0000000013F897A0) ... --- snip ---
time_put_char__Getcat -> time_put_char_ctor_locinfo -> time_put_char__Init -> _Locinfo__Gettnames -> _Gettnames
https://source.winehq.org/git/wine.git/blob/e377786a71c3b6eab5bc11c0b1c9c7c3...
--- snip --- 793 /********************************************************************* 794 * _Gettnames (MSVCRT.@) 795 */ 796 void* CDECL _Gettnames(void) 797 { 798 __lc_time_data *ret, *cur = get_locinfo()->lc_time_curr; 799 unsigned int i, len, size = sizeof(__lc_time_data); 800 801 TRACE("\n"); 802 803 for(i=0; i<ARRAY_SIZE(cur->str.str); i++) 804 size += strlen(cur->str.str[i])+1; 805 806 ret = malloc(size); 807 if(!ret) 808 return NULL; 809 memcpy(ret, cur, sizeof(*ret)); 810 811 size = 0; 812 for(i=0; i<ARRAY_SIZE(cur->str.str); i++) { 813 len = strlen(cur->str.str[i])+1; 814 memcpy(&ret->data[size], cur->str.str[i], len); 815 ret->str.str[i] = &ret->data[size]; 816 size += len; 817 } 818 819 return ret; 820 } --- snip ---
The ANSI parts of the structure get copied - as the function name implies.
Tidbit: A wide-char variant exists as well but is nowhere used. It also seems wrong because it calls the ANSI _Gettnames() which does not copy WCHAR members.
--- snip --- 822 #if _MSVCR_VER >= 110 823 /********************************************************************* 824 * _W_Gettnames (MSVCR110.@) 825 */ 826 void* CDECL _W_Gettnames(void) 827 { 828 return _Gettnames(); 829 } 830 #endif --- snip ---
Back to original problem. At the point of 'strftime_impl', '__lc_time_data' contains only the ANSI members initialized but the 'STRFTIME_TD' macro references WCHAR members for _MSVCR_VER > 90.
https://source.winehq.org/git/wine.git/blob/e377786a71c3b6eab5bc11c0b1c9c7c3...
--- snip --- 853 #if _MSVCR_VER <= 90 854 #define STRFTIME_CHAR char 855 #define STRFTIME_TD(td, name) td->str.names.name 856 #else 857 #define STRFTIME_CHAR wchar_t 858 #define STRFTIME_TD(td, name) td->wstr.names.name 859 #endif --- snip ---
The code was introduced here:
https://source.winehq.org/git/wine.git/commitdiff/c37268f0aa6da3825aa1155153... ("msvcrt: Use correct __lc_time_data fields in strftime functions.")
It's also referenced by bug 50151 ("World of Tanks fails to launch if LC_LANG/LC_ALL are set ja_JP") as regression commit.
I made a separate case here because:
* the app can't reach this code yet (blocker bugs) = nothing to "regress" * doesn't depend on the locale setting * exhibits a different user visible sympthom
$ sha1sum AdobeAudition13All.zip b2800e4fd28f3c669cd0b3754ec11a9e8e18cee1 AdobeAudition13All.zip
$ du -sh AdobeAudition13All.zip 296M AdobeAudition13All.zip
$ wine --version wine-6.0-rc4
Regards