@@ -546,8 +546,26 @@ UINT CallStack::isCrtStartupFunction( LPCWSTR functionName ) const
546546 }
547547
548548 if (endWith (functionName, len, L" DllMainCRTStartup" )
549- || endWith (functionName, len, L" mainCRTStartup" )
550- || beginWith (functionName, len, L" `dynamic initializer for '" )) {
549+ || endWith (functionName, len, L" mainCRTStartup" )
550+
551+ // NOTE: This is tricky...
552+ // This happens for c++ static initialization
553+ // In some cases, we will see
554+ // "namespace::`dynamic initializer for 'symbol'"
555+ // In other cases, there is no namespace prepended, even if the symbol is in a namespace:
556+ // "`dynamic initializer for 'namespace::symbol'"
557+ // This happens above initterm in the stack, which means these statics can be ignored by the code above if they have the namespace
558+
559+ // Ideally, we would ignore dynamic initializers if we (somehow) know there is also a matching "`dynamic atexit destructor for 'symbol'"
560+ // It's possible to use some kind of heuristic to detect this (the stack will have ..., classname::classname, dynamic initializer for, initterm, ...)
561+ // That means that the caller really needs a state machine as we are doing some context-sensitive parsing
562+
563+ // For now, we just make the (possibly wrong) assumption that all dynamic initializations will be cleaned up
564+ // Therefore, the following line is commented out.
565+ // Clearly wrong when we have a global written as "static void* foo = malloc(1);"
566+ // But we can look at a more complex fix if we need to handle that
567+ // || beginWith(functionName, len, L"`dynamic initializer for '")
568+ ) {
551569 // When we reach this point there is no reason going further down the stack
552570 return CALLSTACK_STATUS_NOTSTARTUPCRT;
553571 }
0 commit comments