2023年11月29日发(作者:)
退出线程时由于析构错误引发的崩溃!
Problem: Fatal error thread exit if FLS
callback not freed
kb/2754614
By 唔該正常D
在退出进程之前崩溃,dump显示系统尝试调用一个已经卸载了DLL里的函数,引发崩溃
现象:win7/win2003下,程序在关机时崩溃,有DUMP生成,
错误代码,COM组件释放有问题
Cxx::~Cxx()
{
if (NULL != m_pInterfaceXX)
{
delete m_pInterfaceXX;
m_pInterfaceXX = NULL;
}
}
正确代码应该为
Cxx::~Cxx()
{
if (NULL != m_pInterfaceXX)
{
m_pInterfaceXX->Release();
}
}
A C++ DLL statically linked to CRT may cause a fatal error at thread exit if the DLL load or
unload sequence is interrupted by an unhandled exception.
A process may crash at thread exit with an Access Violation exception (0xC0000005,
EXCEPTION_ACCESS_VIOLATION) if it had dynamically loaded (such as by calling LoadLibrary()) a
native C++ DLL that was statically linked with C Runtime, and the DLL generated an unhandled
exception during its initialization or shutdown.
During the CRT startup or shutdown (such as during DLL_PROCESS_ATTACH or
DLL_PROCESS_DETACH in DllMain(), or in the constructor or destructor of a global/static C++
object), if the DLL generates a fatal error that is unhandled, the LoadLibrary call just swallows the
exception and returns with NULL. When the DLL load or unload fails, some error codes you may
observe include:
ERROR_NOACCESS (998) or EXCEPTION_ACCESS_VIOLATION (0xC0000005, 0n3221225477)
EXCEPTION_INT_DIVIDE_BY_ZERO (0xC0000094, 0n3221225620)
ERROR_STACK_OVERFLOW (1001) or EXCEPTION_STACK_OVERFLOW (0xC00000FD,
C++ exception (0xE06D7363, 0n3765269347)
ERROR_DLL_INIT_FAILED (0x8007045A)
0n3221225725)
This library startup or shutdown failure usually is not observed until the calling thread is about to
*pInt = 5;
break;
}
}
return TRUE;
}
//:
#include
#include
int main(int argc, TCHAR* argv[])
{
HMODULE hModule = LoadLibrary(TEXT(""));
printf("GetLastError = %dn", GetLastError());
if (hModule != NULL)
FreeLibrary(hModule);
return 0;
//Access Violation will occur following the above return statement
}
A Fiber Local Storage (FLS) callback function is invoked by Windows when the thread exits, and
the address of that function is no longer in valid process memory. The most common cause is from
the use of static CRT in a DLL that is prematurely unloaded.
an unhandled exception occurs in the DLL while it is being loaded or unloaded.
Because the C Runtime is statically linked in the DLL, its FLS callback is implemented in that DLL itself.
If this DLL fails to load or unload due to an unhandled exception, not only will the DLL be
automatically unloaded, but the C Runtime’s FLS callback will remain registered with the OS even
after the DLL is unloaded. When the thread exits (e.g., when the EXE’s main() function returns), the
OS tries to invoke the registered FLS callback function (_freefls in this case) which now points to
unmapped process space and ultimately results in an Access Violation exception.
A change has been made in the VC++ 11.0 CRT (in VS 2012) to better address FLS callback cleanup
on unhandled exceptions during DLL startup. So, for DLLs whose source code is accessible and
hence could be recompiled, the following options can be tried:
Compile the DLL with the latest VC11 CRT (i.e., build the DLL with VS2012 RTM).
Use the CRT DLL, rather than static linking to C Runtime while compiling your DLL; use /MD
If possible, correct the cause of the unhandled exception, remove the exception-prone
Implement a custom DLL entry point function, wrapping up CRT’s initialization and code
or /MDd instead of /MT or /MTd.
piece of code from DllMain, and/or handle the exception properly.
to unregister the CRT’s FLS callback if an exception occurs during DLL startup. Note that this
exception handling around the entry point can cause a problem when /GS (buffer security
checks) is used in a debug build. If you choose this option, exclude the exception handling
(using #if or #ifdef) from debug builds.
For DLLs which can’t be rebuilt, there is currently no way to correct this behavior.
This behavior is caused by a failure to unregister an FLS callback into a module that has been
unloaded, so it is caused not only by an unhandled exception during DLL CRT startup or shutdown,
but also by setting up an FLS callback as shown below and not unregistering it before the DLL is
unloaded:
//: To reproduce the problem, compile with static CRT (/MT or /MTd)
#include
VOID WINAPI MyFlsCallback(PVOID lpFlsData)
{
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return 0;
//Access Violation will occur following the above return statement
}
As the FLS callback function is supposed to be called by OS to perform FLS cleanup, the above
invalid function pointer will result in Access Violation exception. Therefore, the ideal resolution to
this issue would be to correct the code itself, ensuring that the FLS callback is unregistered before
the DLL is unloaded.
Note that there may be third party products registered on the runtime machine that will inject DLLs
at runtime into most processes. In such cases, an affected DLL outside of your product development
may lead to this error during thread exit. If you are not in a position to rebuild such DLLs according
to the guidance suggested above, your only option may be to contact the vendor of the product
and request such a fix, or to uninstall the third party product.


发布评论