Почему этот синглтон иногда падает, когда вызывается из DllMain? - PullRequest
4 голосов
/ 03 октября 2019

У меня есть следующий класс, который компилируется в Visual Studio 2015:

class MitigationPolicyChecker
{
public:
    static auto& getInstance()
    {
        static MitigationPolicyChecker instance;
        return instance;
    }

    MitigationPolicyChecker(MitigationPolicyChecker const&) = delete;
    MitigationPolicyChecker(MitigationPolicyChecker&&) = delete;
    MitigationPolicyChecker& operator=(MitigationPolicyChecker const&) = delete;
    MitigationPolicyChecker& operator=(MitigationPolicyChecker&&) = delete;

    bool IsDynamicCodeProhibited();

private:
    MitigationPolicyChecker() = default;
    ~MitigationPolicyChecker() = default;
    void GetDynamicCodePolicy();

    bool m_bDynamicCodeProhibited = false;
};

Этот класс предназначен для запуска из DllMain и проверяет структуру в загруженном образе NtDll, чтобы проверить наличие определенной политики смягчения

В редких случаях (<0,0001% случаев загрузки DLL) этот синглтон вызывает сбой приложения. Однако сбой не связан с тем, что пытается сделать класс, или с хорошо известным списком вещей, которые не разрешены в DllMain (насколько я могу судить). Это связано с созданием самого синглтона. </p>

Стек вызовов в WinDbg выглядит следующим образом:

00 OurDll!MitigationPolicyChecker::getInstance+0x1a
02 OurDll!Initialize+0x79
03 OurDll!DllMain+0x1c9
04 OurDll!dllmain_dispatch+0x74
05 ntdll!LdrpRunInitializeRoutines+0x1fe
06 ntdll!LdrGetProcedureAddressEx+0x2aa
07 ntdll!LdrpCorInitialize+0x1a1
08 ntdll!LdrpInitializeProcess+0x1816
09 ntdll! ?? ::FNODOBFM::`string'+0x22790
0a ntdll!LdrInitializeThunk+0xe

На линии static MitigationPolicyChecker instance

* 1013 происходит нарушение доступа* И аварийная сборочная линия - последняя строка здесь, по-видимому rdx и rcx были равны нулю в соответствии с записью исключения (возможно, сбой локального хранилища потока ??):
0:000> uf OurDll!MitigationPolicyChecker::getInstance
OurDll!MitigationPolicyChecker::getInstance:
    8 000007fe`fbc38ed0 4883ec28           sub     rsp,28h
    9 000007fe`fbc38ed4 b804000000         mov     eax,4
    9 000007fe`fbc38ed9 8bc0               mov     eax,eax
    9 000007fe`fbc38edb 8b0dcf850b00       mov     ecx,dword ptr [OurDll!_tls_index (000007fe`fbcf14b0)]
    9 000007fe`fbc38ee1 65488b142558000000 mov   rdx,qword ptr gs:[58h]
    9 000007fe`fbc38eea 488b0cca           mov     rcx,qword ptr [rdx+rcx*8]

Так что здесь происходит? У процесса есть только один активный поток во время сбоя, поэтому я не думаю, что это проблема параллелизма. Насколько я знаю:

  1. Статический объект должен быть создан при первом доступе.
  2. Статика обычно инициализируется непосредственно перед DllMain, но в этом случае, поскольку это функцияна уровне статики он будет создан при вызове, а поскольку он VS2015, он будет создан как «магическая статика».

Есть ли что-то, чего мне не хватает, что делает это небезопасным?

...