Zugriffsverletzung bei statischer Initialisierung

Ich arbeite mit Visual Studio 2015 unter Windows 7 an einer Anwendung. Die Anwendung verfügt über ein C # -Frontend, einen C ++ - CLR-Wrapper und systemeigenen C ++ - Code.

Meine Anwendung stürzt mit einer Zugriffsverletzung ab, während eine statische Variable im Funktionsumfang mit systemeigenem C ++ - Code initialisiert wird. Aber nur unter Windows Server 2003 Enterprise SP2 und nicht unter Windows 7 oder Windows Server 2012. Ich weiß, dass Windows Server 2003 nicht mehr unterstützt wird, aber ich muss diese Plattform für ein paar zusätzliche Monate als Ziel festlegen, und Visual Studio 2015 bietet ein Plattform-Toolset für das Ziel es

Ich habe ein kleines reproduzierbares Beispiel erstellt, das Sie am Ende finden.

Der Absturz tritt nur bei allen drei beteiligten Teilen auf (C #, C ++ CLR, C ++). Wenn ich welche entferne, ist der Absturz weg.

Der Absturz tritt nur mit einem definierten benutzerdefinierten Konstruktor auf. Wenn ich den Konstruktor entferne, ist der Absturz weg.

Ich bin kein Assembler-Experte, aber für mich sieht es so aus, als würde der Absturz durch den Code verursacht, der prüft, ob die statische Initialisierung erforderlich ist. Der Konstruktor wird nicht einmal aufgerufen.

Meine Frage lautet: Warum stürzt es unter Windows Server 2003 ab? Fehlt mir eine wichtige Projekteinstellung?

Die Fehlermeldung
Unhandled exception at 0x1000167E (Native.dll) in Managed.exe.dmp: 0xC0000005: Access violation reading location 0x00000000.
Visual C # -Konsolenanwendung "Managed.exe" Program.cs
// Target framework: .NET Framework 4
// Platform target: x86

using System;

namespace Managed
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Press enter to start test...");
            Console.ReadLine();

            Native.Wrapper wrapper = new Native.Wrapper();
            Console.WriteLine("Test was successful");

            Console.Write("Press enter to exit...");
            Console.ReadLine();
        }
    }
}
Visual C ++ CLR Class Library "Native.dll" Wrapper.hpp
#pragma once

namespace Native
{

public ref class Wrapper
{
public:
    Wrapper();

}; // public ref class Wrapper

} // namespace Native
Wrapper.cpp
// Platform Toolset: Visual Studio 2015 - Windows XP (v140_xp)
// Common Language Runtime Support: Common Language Runtime Support (/clr)
// .NET Target Framework Version: v4.0
// Warning Level: Level4
// Treat Warnings As Errors: Yes (/WX)
// Precompiled Header: Not Using Precompiled Headers
// SubSystem: Console (/SUBSYSTEM:CONSOLE)
// Optimization: Disabled (/Od)

#pragma once

#include "Wrapper.hpp"
#include "Caller.hpp"

namespace Native
{

Wrapper::Wrapper()
{
    Caller* caller = new Caller();
    delete caller;
}

} // namespace Native
Caller.hpp
#pragma once

namespace Native
{

class Caller
{
public:
    Caller();

}; // class Caller

} // namespace Native
Caller.cpp
// Platform Toolset: Visual Studio 2015 - Windows XP (v140_xp)
// Common Language Runtime Support: No Common Language RunTime Support
// Warning Level: Level4
// Treat Warnings As Errors: Yes (/WX)
// Precompiled Header: Not Using Precompiled Headers
// SubSystem: Console (/SUBSYSTEM:CONSOLE)
// Optimization: Disabled (/Od)

#include "Caller.hpp"
#include "Singleton.hpp"

namespace Native
{

Caller::Caller()
{
    Singleton::GetInstance()->DoSomething();
}

} // namespace Native
Singleton.hpp
#pragma once

#include <iostream>

namespace Native
{

class Singleton
{
public:
    Singleton() // !!! remove constructor to prevent crash !!!
    { }

    static Singleton* GetInstance()
    {
        static Singleton Instance; // !!! crashes here !!!
        return &Instance;
    }

    void DoSomething()
    {
        std::wcout << L"Doing something...\n";
    }

}; // class Singleton

} // namespace Native
Die Demontage
    static Singleton* GetInstance()
    {
10001650  push        ebp  
10001651  mov         ebp,esp  
10001653  push        0FFFFFFFFh  
10001655  push        10006A8Ch  
1000165A  mov         eax,dword ptr fs:[00000000h]  
10001660  push        eax  
10001661  mov         eax,dword ptr ds:[1001B334h]  
10001666  xor         eax,ebp  
10001668  push        eax  
10001669  lea         eax,[ebp-0Ch]  
1000166C  mov         dword ptr fs:[00000000h],eax  
        static Singleton Instance;
10001672  mov         eax,dword ptr ds:[1001B5D0h]  
10001677  mov         ecx,dword ptr fs:[2Ch]  
1000167E  mov         edx,dword ptr [ecx+eax*4] // !!! access violation here !!!
10001681  mov         eax,dword ptr ds:[1001B5A4h]  
10001686  cmp         eax,dword ptr [edx+4]  
1000168C  jle         Native::Singleton::GetInstance+79h (100016C9h)  
Die Register
EAX = 00000000 EBX = 00000000 ECX = 00000000 EDX = 006A0003 ESI = 001647C8
EDI = 0012F3BC EIP = 1000167E ESP = 0012F394 EBP = 0012F3A4 EFL = 00010282 
Edit 1

Während Sie lokal debuggen, wo der Absturz nicht auftritt, werden in der Assembly einige weitere Symbole angezeigt:

    static Singleton* GetInstance()
    {
0FBD1650  push        ebp  
0FBD1651  mov         ebp,esp  
0FBD1653  push        0FFFFFFFFh  
0FBD1655  push        offset __ehhandler$?GetInstance@Singleton@Native@@SAPAV12@XZ (0FBD86BCh)  
0FBD165A  mov         eax,dword ptr fs:[00000000h]  
0FBD1660  push        eax  
0FBD1661  mov         eax,dword ptr [___security_cookie (0FBF03CCh)]  
0FBD1666  xor         eax,ebp  
0FBD1668  push        eax  
0FBD1669  lea         eax,[ebp-0Ch]  
0FBD166C  mov         dword ptr fs:[00000000h],eax  
        static Singleton Instance;
0FBD1672  mov         eax,dword ptr [__tls_index (0FBF0668h)]  
0FBD1677  mov         ecx,dword ptr fs:[2Ch]  
0FBD167E  mov         edx,dword ptr [ecx+eax*4]  
0FBD1681  mov         eax,dword ptr [TSS0<`template-parameter-2',Native::Singleton::tInstance,Native::Singleton * * const volatile,void,int, ?? &> (0FBF063Ch)]  
0FBD1686  cmp         eax,dword ptr [edx+4]  
0FBD168C  jle         Native::Singleton::GetInstance+79h (0FBD16C9h)  

Das Symbol__tls_index scheint zu einem lokalen Thread-Speicher zu gehören (nach dem Namen erraten). Das passt zuMagic statics verwendet den lokalen Threadspeicher als Leistungsoptimierung in der Referenzimplementierung. Bei einem Absturz gibt der lokale Threadspeicher @ zurüc0.

Kann dies ein Fehler in der Laufzeitumgebung unter Windows Server 2003 sein, die den lokalen Threadspeicher verwaltet und initialisiert?

Edit 2

Wird über Microsoft Connect als Fehler gemeldet:Fehlerberich

Antworten auf die Frage(4)

Ihre Antwort auf die Frage