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 Runtimes FLS callback will remain registered with the OS even

after the DLL is unloaded. When the thread exits (e.g., when the EXEs 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 CRTs initialization and code

or /MDd instead of /MT or /MTd.

piece of code from DllMain, and/or handle the exception properly.

to unregister the CRTs 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 cant 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.