Closed mingkuang-Chuyu closed 3 years ago
https://github.com/Chuyu-Team/YY-Thunks/releases/tag/v1.0.3-Beta1
已经修复此问题,YY-Thunks将预加载所有try_get函数。
是不是只需要确保 kernel32 加载即可
解决这个死锁缺少只要加载kernel32 即可。但是在其他场景加载DLL时这任然可能出现其他死锁。
以最坏情况,也只是跟原始行为一样而已。在没有更好的解决方案之前,性能 以及 死锁风险里我选择避免死锁风险。
死锁场景:
线程A:Thread创建回调 -->DLL Load锁定 --> tdp初始化 --> 等待locale锁
`DLL Load锁定` 这个是YY-Thunks里面的load吗?
线程B:locale锁定 --> _Atexit --> EncodePointer(YY-Thunks) --> 等待 DLL Load锁
从这个感觉是不是把 try_get_module 枷锁即可
try_get_module()
{
enter_critical_section
do get module
exit_critical_section
}
感觉问题的根源在于 Dynamic-Link库最佳做法
以及 https://www.zhihu.com/question/22720399/answer/22401573 也就是要避免在 DllMain 里面调用 LoadLibrary 或 LoadLibraryEx 所以正确的做法是 对于 ntdll 和kernel32 使用 GetModuleHandleW, 对于其它的dll,在需要使用的时候在加载
死锁场景:
线程A:Thread创建回调 -->DLL Load锁定 --> tdp初始化 --> 等待locale锁 `DLL Load锁定` 这个是YY-Thunks里面的load吗? 线程B:locale锁定 --> _Atexit --> EncodePointer(YY-Thunks) --> 等待 DLL Load锁
从这个感觉是不是把 try_get_module 枷锁即可
try_get_module() { enter_critical_section do get module exit_critical_section }
你是认真的吗?
感觉问题的根源在于 Dynamic-Link库最佳做法
以及 https://www.zhihu.com/question/22720399/answer/22401573 也就是要避免在 DllMain 里面调用 LoadLibrary 或 LoadLibraryEx 所以正确的做法是 对于 ntdll 和kernel32 使用 GetModuleHandleW, 对于其它的dll,在需要使用的时候在加载
VirtualQuery
魔法拿到的也是个不稳定的kernelbase,不适合YY-Thunks的场景。
最佳实践?我们只能从中选择现在没有遇到问题的路……
即使是微软CRT,任然也任然在DLLMain里LoadDLL。
感觉问题的根源在于 Dynamic-Link库最佳做法 以及 https://www.zhihu.com/question/22720399/answer/22401573 也就是要避免在 DllMain 里面调用 LoadLibrary 或 LoadLibraryEx 所以正确的做法是 对于 ntdll 和kernel32 使用 GetModuleHandleW, 对于其它的dll,在需要使用的时候在加载
对于Win7,GetModuleHandleW任然会入锁,并不会变得更好,此外不用GetModuleHandleW改成用
VirtualQuery
魔法拿到的也是个不稳定的kernelbase,不适合YY-Thunks的场景。
- 唯一安全的是DllMain里调用GetModuleHandle,这个是安全的。因为当前线程已经取得锁,不会引入更多锁。
- 此外需要时使用,这可能会产生死锁,死锁的原因就在于CRT会初始化时锁定了locale。一旦其他locale锁定代码里依赖复杂的代码这又会导致无法控制,出现死锁风险。
- 某些进程拥有沙箱,按需加载也会导致按需时加载失败。
最佳实践?我们只能从中选择现在没有遇到问题的路……
因为遇到问题了,我有个c++测试程序在win7下,在load pdh.DLL 和 shell32.dll的时候直接蹦了
即使是微软CRT,任然也任然在DLLMain里LoadDLL。
微软不是有delay laod 机制吗 那个也是在调用的时候才加载的吧,
CRT 我看用的是 get module handle 对于 ntdll 和 kernel32,其它的 我至少调试的时候没发现 dllmain 里面有 load dll,
ucrt 是通过__acrt_eagerly_load_locale_apis 来解决锁的问题,并且在 DllMain里面并没有加载任何库
// This function simply attempts to get each of the locale-related APIs. This
// allows a caller to "pre-load" the modules in which these APIs are hosted. We
// use this in the _wsetlocale implementation to avoid calls to LoadLibrary while
// the locale lock is held.
extern "C" void __cdecl __acrt_eagerly_load_locale_apis()
{
try_get_AreFileApisANSI();
try_get_CompareStringEx();
try_get_EnumSystemLocalesEx();
try_get_GetDateFormatEx();
try_get_GetLocaleInfoEx();
try_get_GetTimeFormatEx();
try_get_GetUserDefaultLocaleName();
try_get_IsValidLocaleName();
try_get_LCMapStringEx();
try_get_LCIDToLocaleName();
try_get_LocaleNameToLCID();
}
麻烦你调试一下 __acrt_eagerly_load_locale_apis
在什么时机被加载,虽然不是真的DllMain,但是也差不多,在CRT DllMain的入口。
感觉问题的根源在于 Dynamic-Link库最佳做法 以及 https://www.zhihu.com/question/22720399/answer/22401573 也就是要避免在 DllMain 里面调用 LoadLibrary 或 LoadLibraryEx 所以正确的做法是 对于 ntdll 和kernel32 使用 GetModuleHandleW, 对于其它的dll,在需要使用的时候在加载
对于Win7,GetModuleHandleW任然会入锁,并不会变得更好,此外不用GetModuleHandleW改成用
VirtualQuery
魔法拿到的也是个不稳定的kernelbase,不适合YY-Thunks的场景。
- 唯一安全的是DllMain里调用GetModuleHandle,这个是安全的。因为当前线程已经取得锁,不会引入更多锁。
- 此外需要时使用,这可能会产生死锁,死锁的原因就在于CRT会初始化时锁定了locale。一旦其他locale锁定代码里依赖复杂的代码这又会导致无法控制,出现死锁风险。
- 某些进程拥有沙箱,按需加载也会导致按需时加载失败。
最佳实践?我们只能从中选择现在没有遇到问题的路……
因为遇到问题了,我有个c++测试程序在win7下,在load pdh.DLL 和 shell32.dll的时候直接蹦了
即使是微软CRT,任然也任然在DLLMain里LoadDLL。
微软不是有delay laod 机制吗 那个也是在调用的时候才加载的吧,
CRT 我看用的是 get module handle 对于 ntdll 和 kernel32,其它的 我至少调试的时候没发现 dllmain 里面有 load dll,
@lygstate 如果你发现崩溃,那么可以单独创建崩溃Bug,我们可以想办法解决。
LoadLibraryExW
。__acrt_eagerly_load_locale_apis
的发生在广义的DllMain
里,你总不能因为调用链路上没有DllMain
所以说CRT DllMain没有LoadDll吧?如果是这样,那么YY-Thunks
加载工作也不在DllMain
里……最后我并不是说现在YY-Thunks这样做是合理的,我也不是说你说的没有道理,主要问题在于,延迟加载同样也是不合理的…… 但是描述问题我们任然需要实事求是。
嗯,大致就这样吧。如果YY-Thunks遇到崩溃等问题可以再提Bug。
Vsitual Studio 2017 + Windows XP模式 + MT 运行环境:Windows 7 x64
死锁场景: 线程A:Thread创建回调 -->DLL Load锁定 --> tdp初始化 --> 等待locale锁 线程B:locale锁定 --> _Atexit --> EncodePointer(YY-Thunks) --> 等待 DLL Load锁