[Bug 50409] New: 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)

WineHQ Bugzilla wine-bugs at winehq.org
Sun Dec 27 05:44:06 CST 2020


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 at winehq.org
          Reporter: focht at 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 at DU?$char_traits at D@std@@@std@@IEBAPEADXZ(0021eca8)
ret=180040fdc
0104:trace:msvcp:basic_streambuf_char_pptr (000000000021ECA8)
0104:Ret 
msvcp140.?pptr@?$basic_streambuf at DU?$char_traits at 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 at DU?$char_traits at D@std@@@std@@IEAAPEADXZ(0021eca8)
ret=180041127
0104:trace:msvcp:basic_streambuf_char__Pninc (000000000021ECA8)
0104:Ret 
msvcp140.?_Pninc@?$basic_streambuf at DU?$char_traits at 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/e377786a71c3b6eab5bc11c0b1c9c7c3dc309398:/dlls/msvcrt/time.c#l1081

--- 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/e377786a71c3b6eab5bc11c0b1c9c7c3dc309398:/dlls/msvcrt/msvcrt.h#l47

--- 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/e377786a71c3b6eab5bc11c0b1c9c7c3dc309398:/dlls/msvcrt/locale.c#l793

--- 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/e377786a71c3b6eab5bc11c0b1c9c7c3dc309398:/dlls/msvcrt/time.c#l853

--- 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/c37268f0aa6da3825aa11551537b8e18aa62bdca
("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

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.


More information about the wine-bugs mailing list