вторник, 21 августа 2012 г.

sprintf_s - wtf ?

Lets assume that we set some handler with LdrRegisterDllNotification and just dump all (un)loaded modules to log file. Access to this log is synchronized with critical section - lets name it LogFileCSection. Today I discovered that this simple scheme can lead to unpredictable deadlocks:
thread 1:

02fbd09c 77c88dd4 ntdll_77c50000!ZwWaitForSingleObject+0x15
02fbd100 77c88cb8 ntdll_77c50000!RtlpWaitOnCriticalSection+0x13e
02fbd128 6c4d6144 ntdll_77c50000!RtlEnterCriticalSection+0x150 ; waits on
LogFileCSection
02fbd1e0 6c4baf66 xxx!log_with_time+0x22
02fbd210 77cb76b8 xxx!my_notifier+0x36
02fbd240 77c8c74a ntdll_77c50000!LdrpSendDllNotifications+0x45
02fbd328 77c8c389 ntdll_77c50000!LdrpFindOrMapDll+0x735
02fbd4a8 77c8c4b5 ntdll_77c50000!LdrpLoadDll+0x2b2
02fbd4e0 759a1d2a ntdll_77c50000!LdrLoadDll+0xaa ; LdrpLoaderLock acquired
02fbd518 7741493c KERNELBASE!LoadLibraryExW+0x178
02fbd52c 6b268546 KERNEL32!LoadLibraryW+0x11
02fbd540 6b261404 IEFRAME!GetDloadFunction+0x20
02fbd55c 6b261623 IEFRAME!DwmSetWindowAttribute+0x2f
02fbd580 6b2615bd IEFRAME!CTabThumbnailHandler::_OnCreate+0x45
02fbd59c 6b2d7e17 IEFRAME!CTabThumbnailHandler::v_WndProc+0xa0
02fbd5c0 766c62fa IEFRAME!CImpWndProc::s_WndProc+0x65
02fbd5ec 766c6d3a USER32!InternalCallWinProc+0x23
02fbd664 766c6de8 USER32!UserCallWinProcCheckWow+0x109
02fbd6c0 766ca740 USER32!DispatchClientMessage+0xe0
02fbd700 77c6011a USER32!__fnINLPCREATESTRUCT+0x91
02fbd780 766ca8e8 ntdll_77c50000!KiUserCallbackDispatcher+0x2e
02fbda2c 766caa3c USER32!VerNtUserCreateWindowEx+0x1a9
02fbdae0 766c8a5c USER32!_CreateWindowEx+0x210
02fbdb1c 6b293892 USER32!CreateWindowExW+0x33
02fbdb5c 6b24ad22 IEFRAME!Detour_CreateWindowExW+0x6a
02fbdb9c 6b261adb IEFRAME!SHFusionCreateWindowEx+0x47
02fbdcec 6b2619f6 IEFRAME!CTabThumbnailHandler::_Initialize+0xc6
02fbdcfc 6b261118 IEFRAME!CTabThumbnailHandler::CreateInstance+0x3f
02fbdd2c 6b284a68 IEFRAME!CShellBrowser2::AfterWindowCreated+0x9c
02fbfe40 6b294f7a IEFRAME!CTabWindow::_TabWindowThreadProc+0x23c
02fbfef8 76215c2b IEFRAME!LCIETab_ThreadProc+0x2c1
02fbff08 774133ca iertutil!CIsoScope::RegisterThread+0xab
02fbff14 77c89ed2 KERNEL32!BaseThreadInitThunk+0xe


thread 2:

030eef30 77c88dd4 ntdll_77c50000!ZwWaitForSingleObject+0x15
030eef94 77c88cb8 ntdll_77c50000!RtlpWaitOnCriticalSection+0x13e
030eefbc 77c7ffb3 ntdll_77c50000!RtlEnterCriticalSection+0x150 ; waits on LdrpLoaderLock
030ef12c 77c7fd0f ntdll_77c50000!LdrGetDllHandleEx+0x2f7
030ef148 759a0dae ntdll_77c50000!LdrGetDllHandle+0x18
030ef19c 759a0fc2 KERNELBASE!GetModuleHandleForUnicodeString+0x22
030ef614 759a10bd KERNELBASE!BasepGetModuleHandleExW+0x181
030ef62c 6c4dc11c KERNELBASE!GetModuleHandleW+0x29
030ef63c 6c4dc172 xxx!_decode_pointer+0x45 [f:\dd\vctools\crt_bld\self_x86\crt\src\tidtable.c @ 172]
030ef648 6c4dc2c1 xxx!__set_flsgetvalue+0x20 [f:\dd\vctools\crt_bld\self_x86\crt\src\tidtable.c @ 259]
030ef658 6c4dc32b xxx!_getptd_noexit+0x17 [f:\dd\vctools\crt_bld\self_x86\crt\src\tidtable.c @ 578]
030ef660 6c4d8ee2 xxx!_getptd+0x8 [f:\dd\vctools\crt_bld\self_x86\crt\src\tidtable.c @ 641]
030ef66c 6c4e262e xxx!_LocaleUpdate::_LocaleUpdate+0x18 [f:\dd\vctools\crt_bld\self_x86\crt\src\setlocal.h @ 264]
030ef8fc 6c4e1150 xxx!_output_s_l+0x67 [f:\dd\vctools\crt_bld\self_x86\crt\src\output.c @ 2155]
030ef940 6c4e11ee xxx!_vsnprintf_helper+0x89 [f:\dd\vctools\crt_bld\self_x86\crt\src\vsprintf.c @ 140]
030ef968 6c4da368 xxx!_vsprintf_s_l+0x5b [f:\dd\vctools\crt_bld\self_x86\crt\src\vsprintf.c @ 236]
030ef984 6c4d618e xxx!sprintf_s+0x19 [f:\dd\vctools\crt_bld\self_x86\crt\src\sprintf.c @ 215]
030efa60 6c4bc7ca xxx!log_with_time+0x22 ;
LogFileCSection acquired
...
030efc38 77c954f4 ntdll_77c50000!RtlpTpWorkCallback+0x11d
030efd98 774133ca ntdll_77c50000!TppWorkerThread+0x572
030efda4 77c89ed2 KERNEL32!BaseThreadInitThunk+0xe


Thread 2 acquired critical section LogFileCSection and called sprintf_s which somewhere inside try to call LdrGetDllHandle(Ex) and wait for LdrpLoaderLock. In the same time thread 1 got notification about dll loading and call (with acquired LdrpLoaderLock) EnterCriticalSection(LogFileCSection) to sync file access. So we have classical deadlock. Reason is that function sprintf_s calls GetModuleHandleW

And what to do to avoid it ?

Комментариев нет:

Отправить комментарий