Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

to_string( stacktrace ) gets stuck if first called during DLL loading #4675

Closed
Fedr opened this issue May 14, 2024 · 3 comments
Closed

to_string( stacktrace ) gets stuck if first called during DLL loading #4675

Fedr opened this issue May 14, 2024 · 3 comments
Labels
bug Something isn't working invalid This issue is incorrect or by design

Comments

@Fedr
Copy link

Fedr commented May 14, 2024

Describe the bug

If to_string( std::stacktrace::current() ) first called during DLL loading, then the application can hang forever.

Test case

Put a global variable in your DLL calling to_string( std::stacktrace::current() ) in its constructor:

struct A {
    A() {
        (void)to_string( std::stacktrace::current() );
    }
} a_;

then during loading of this DLL by means of LoadLibraryW, for example, on Windows 11 the program hangs with the stack as follows:

ntdll.dll!NtWaitForSingleObject()
KernelBase.dll!WaitForSingleObjectEx()
winnsi.dll!NsiRpcRegisterChangeNotificationEx()
winnsi.dll!NsiRpcRegisterChangeNotification()
IPHLPAPI.DLL!InternalRegisterChangeNotification()
IPHLPAPI.DLL!NotifyIpInterfaceChange()
cryptnet.dll!I_CryptNetGetConnectivity()
crypt32.dll!ChainGetConnectivity(void)
crypt32.dll!CChainCallContext::IsConnected(void)
crypt32.dll!CCertChainEngine::TriggerPreFetch()
crypt32.dll!CCertChainEngine::GetChainContext()
crypt32.dll!CertGetCertificateChain()
wintrust.dll!_WalkChain()
wintrust.dll!WintrustCertificateTrust()
wintrust.dll!I_VerifyTrust()
wintrust.dll!WinVerifyTrust()
dbgeng.dll!DbgWinVerifyTrust(struct HWND__ *,struct _GUID *,void *)
dbgeng.dll!VerifyFileSignature(unsigned short const *)
dbgeng.dll!ExtensionSecurityValidate()
dbgeng.dll!ExtensionInfo::Load(class DebugClient *,class TargetInfo *,unsigned short const *,bool)
dbgeng.dll!TargetInfo::AddSpecificExtensions(class DebugClient *)
dbgeng.dll!NotifyDebuggeeActivation(void)
dbgeng.dll!LiveUserTargetInfo::WaitForEvent(unsigned long,unsigned long,unsigned long,unsigned long *)
dbgeng.dll!WaitForAnyTarget(unsigned long,unsigned long,unsigned long,unsigned long,unsigned long *)
dbgeng.dll!RawWaitForEvent(class DebugClient *,unsigned long,unsigned long)
dbgeng.dll!DebugClient::WaitForEvent()
MyDLL.dll!`anonymous namespace'::dbg_eng_data::try_initialize() Line 113    C++
MyDLL.dll!__std_stacktrace_to_string(const void * const * const _Addresses, const unsigned __int64 _Size, void * const _Str, unsigned __int64(*)(unsigned __int64, void *, void *, unsigned __int64(*)(char *, unsigned __int64, void *) noexcept) _Fill) Line 306  C++
MyDLL.dll!std::to_string(const std::basic_stacktrace<std::allocator<std::stacktrace_entry>> &) Line 343 C++
MyDLL.dll!A::{ctor}() Line 265  C++
MyDLL.dll!`dynamic initializer for 'a_''() Line 267 C++
ucrtbase.dll!_initterm()
MyDLL.dll!dllmain_crt_process_attach(HINSTANCE__ * const instance, void * const reserved) Line 66   C++
...

Expected behavior

I would expect that to_string( stacktrace ) will return an empty string or an error, but does not get stuck.

STL version

Visual Studio 2022 version 17.9.2

Additional context

The problem is that I try logging stacktraces in my exception handler, which can be invoked during DLL loading as well (and global object is just to simplify demonstration). It is extremely inconvenient that I must track by myself the moments when stacktrace can be used and when it is not because of possible hangs.

@AlexGuteniev
Copy link
Contributor

Recreated.

I happen to contribute the <stacktrace> feature, and I have no clear idea what is going on and how to fix it.

Generally, arbitrary API's are not supported in DllMain because of the loader lock problem.
See Dynamic-Link Library Best Practices.

However, I don't see this hang as an occurrence of the loader lock problem, it looks like something else.

Also, I don't see a documented way how to detect the problematic situation. A call from DllMain can be detected by querying loader lock state. But there's no documented way to query the loader lock state. Also, it is not clear ow strictly this problem is connected with DllMain.

It is possible that switching the implementation from DbgEng.dll to DbgHelp.dll can fix the problem, because on <stacktrace> implementation side it hangs in this place, which would not be needed in case of DbgHelp.dll usage:

STL/stl/src/stacktrace.cpp

Lines 101 to 103 in 8dc4faa

if (attached) {
(void) debug_control->WaitForEvent(0, INFINITE);
}

Maybe it can be seen better from maintainers' side with Windows source available.

@StephanTLavavej StephanTLavavej added the bug Something isn't working label May 15, 2024
@StephanTLavavej
Copy link
Member

This looks by design to me - even if the loader lock specifically isn't the cause, calling STL functions during DLL attach is fraught with peril because of the loader lock, so I don't think we can support it in general. I'm not a DLL expert though, so I'll leave this issue open for now.

@StephanTLavavej StephanTLavavej added the decision needed We need to choose something before working on this label May 15, 2024
@StephanTLavavej StephanTLavavej removed the decision needed We need to choose something before working on this label May 22, 2024
@StephanTLavavej
Copy link
Member

We talked about this at the weekly maintainer meeting and concluded that this is by design - we can't support stringizing stacktraces during DLL attach.

@StephanTLavavej StephanTLavavej closed this as not planned Won't fix, can't repro, duplicate, stale May 22, 2024
@StephanTLavavej StephanTLavavej added the invalid This issue is incorrect or by design label May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working invalid This issue is incorrect or by design
Projects
None yet
Development

No branches or pull requests

3 participants