静态初始化时访问冲突 [英] Access violation on static initialization

查看:213
本文介绍了静态初始化时访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows 7上使用Visual Studio 2015开发应用程序。应用程序有一个C#前端,一个C ++ CLR包装器和C ++本地代码。



在使用C ++本机代码初始化函数范围内的静态变量时,会发生访问冲突。但是只在Windows Server 2003 Enterprise SP2上,而不是在Windows 7或Windows Server 2012.我知道Windows Server 2003是不支持,但我必须定位该平台几个月,Visual Studio 2015提供了一个平台工具集的目标



我创建了一个小的可重现的例子,你在结尾找到。



崩溃只发生在所有三个部分涉及(C#,C ++ CLR,C ++)。如果我删除任何,崩溃都消失了。



崩溃只发生在定义的自定义构造函数。如果我删除构造函数,崩溃就消失了。



我不是装配专家,但对我来说,看起来像崩溃是由代码检查是否静态需要初始化。构造函数甚至不被调用。



我的问题是:为什么它在Windows Server 2003上崩溃?我缺少一些重要的项目设置?



错误消息



  Managed.exe.dmp中的0x1000167E(Native.dll)未处理的异常:0xC0000005:访问冲突读取位置0x00000000。 



Visual C#控制台应用程序Managed.exe



Program.cs



  //目标框架:.NET Framework 4 
//平台目标:x86

使用System;

命名空间管理
{
类程序
{
static void Main(string [] args)
{
控制台。写(按Enter键开始测试...);
Console.ReadLine();

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

Console.Write(按Enter键退出...);
Console.ReadLine();
}
}
}



Visual C ++ CLR类库 Native.dll



Wrapper.hpp



  #pragma once 

命名空间native
{

public ref class Wrapper
{
public:
Wrapper );

}; // public ref class Wrapper

} //命名空间Native



包装器。 cpp



  //平台工具集:Visual Studio 2015  -  Windows XP(v140_xp)
//公共语言运行时支持:公共语言运行时支持(/ clr)
// .NET目标框架版本:v4.0
//警告级别:Level4
//将警告视为错误:是(/ WX)
//预编译头:不使用预编译头
//子系统:控制台(/ SUBSYSTEM:CONSOLE)
//优化:Disabled(/ Od)

#pragma once

#includeWrapper.hpp
#includeCaller.hpp

命名空间native
{

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

} //命名空间Native



Caller.hpp



  #pragma once 

namespace Native
{

class Caller
{
public:
Caller();

}; // class Caller

} //命名空间Native



Caller.cpp



  //平台工具集:Visual Studio 2015  -  Windows XP(v140_xp)
//公共语言运行时支持:无公共语言RunTime支持
//警告级别:Level4
//将警告作为错误处理:是(/ WX)
//预编译头:未使用预编译头b $ b // SubSystem:Console(/ SUBSYSTEM:CONSOLE)
//优化:Disabled(/ Od)

#includeCaller.hpp
#includeSingleton .hpp

命名空间native
{

Caller :: Caller()
{
Singleton :: GetInstance() - >做一点事();
}

} //命名空间Native



Singleton.hpp



  #pragma once 

#include< iostream>

命名空间本地
{

类Singleton
{
public:
Singleton()//!删除构造函数以防止崩溃!
{}

static Singleton * GetInstance()
{
static Singleton Instance; // !!!崩溃这里!
return& Instance;
}

void DoSomething()
{
std :: wcout< L做某事... \\\
;
}

}; // class Singleton

} //命名空间Native



h1>

  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实例;
10001672 mov eax,dword ptr ds:[1001B5D0h]
10001677 mov ecx,dword ptr fs:[2Ch]
1000167E mov edx,dword ptr [ecx + eax * 4] !访问违规这里!
10001681 mov eax,dword ptr ds:[1001B5A4h]
10001686 cmp eax,dword ptr [edx + 4]
1000168C jle Native :: Singleton :: GetInstance + 79h(100016C9h)



寄存器



  EAX = 00000000 EBX = 00000000 ECX = 00000000 EDX = 006A0003 ESI = 001647C8 
EDI = 0012F3BC EIP = 1000167E ESP = 0012F394 EBP = 0012F3A4 EFL = 00010282



编辑1



在本地调试时不会发生崩溃,还有几个符号在程序集中可见:

  static Singleton * GetInstance b {
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)
pre>

符号 __ tls_index 似乎属于某些线程本地存储(从名称猜出)。这与魔法静态相符,后者使用线程本地存储作为参考实现中的性能优化。当崩溃时,线程本地存储返回 0



这可能是Windows Server上运行时环境的错误2003



编辑2



通过Microsoft Connect报告为错误:

a href =https://connect.microsoft.com/VisualStudio/feedback/details/1789709/visual-c-2015-runtime-broken-on-windows-server-2003-c-11-magic-statics = nofollow>错误报告

解决方案

这是Microsoft的答复发布到我的搜索报告在Microsoft Connect:


Windows Server 2003和Windows XP在使用线程本地存储的动态加载DLL(通过LoadLibrary) ,这是线程安全静态使用内部提供高效执行时静态局部已经初始化。由于这些系统不支持,因此不太可能为这些系统创建补丁以添加此支持,就像Vista和更新的操作系统中一样,我们不愿意惩罚在支持操作系统上的性能,以提供此支持



要解决这个问题,您可以使用/ Zc:threadSafeInit-来禁用线程安全的初始化代码,这将会避免线程局部变量。当然,通过这样做,初始化代码恢复到VS2013模式,并且不是线程安全的,所以这个选项只有在你不依赖于本地静态的线程安全性时才可行。



I am working on an application with Visual Studio 2015 on Windows 7. The application has a C# frontend, a C++ CLR wrapper and C++ native code.

My application crashes with an access violation while initializing a static variable at function scope with C++ native code. But only on Windows Server 2003 Enterprise SP2 and not on Windows 7 or Windows Server 2012. I know Windows Server 2003 is out of support, but I have to target that platform for a few additional months and Visual Studio 2015 provides a platform toolset to target it.

I created a small reproducible example which you find at the end.

The crash only happens with all three parts involved (C#, C++ CLR, C++). If I remove any, the crash is gone.

The crash only happens with a custom constructor defined. If I remove the constructor, the crash is gone.

I am no assembly expert, but for me it looks like the crash is caused by the code which checks if the static initialization is required. The constructor is not even called.

My question is: Why does it crash on Windows Server 2003? Am I missing some important project setting?

The error message

Unhandled exception at 0x1000167E (Native.dll) in Managed.exe.dmp: 0xC0000005: Access violation reading location 0x00000000.

Visual C# Console Application "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

The disassembly

    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)  

The registers

EAX = 00000000 EBX = 00000000 ECX = 00000000 EDX = 006A0003 ESI = 001647C8
EDI = 0012F3BC EIP = 1000167E ESP = 0012F394 EBP = 0012F3A4 EFL = 00010282 

Edit 1

While debugging locally where the crash does not happen, a few more symbols are visible with the assembly:

    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)  

The symbol __tls_index seems to belong to some thread local store (guessed from the name). This matches with Magic statics which uses thread local store as a performance optimization in the reference implementation. When crashing, the thread local store returns 0.

Could this be a bug with the runtime environment on Windows Server 2003 which manages and initializes the thread local store?

Edit 2

Reported as bug through Microsoft Connect: Bug report

解决方案

This is the answer of Microsoft as posted to my bug report at Microsoft Connect:

Windows Server 2003 and Windows XP have problems with dynamically loading a DLL (via LoadLibrary) that uses thread-local storage, which is what thread-safe statics use internally to provide efficient execution when the static local has already been initialized. As these systems are out of support, it is extremely unlikely for a patch to be created for those systems to add this support as is present in Vista and newer OSes, and we are reluctant to penalize the performance on in-support OSes to provide this functionality to the old out-of-support ones.

To work around the issue you can use /Zc:threadSafeInit- to disable the thread-safe initialization code and this will avoid the thread-local variable. Of course by doing so the initialization code reverts back to the VS2013 mode and is not thread-safe, so this option is only viable if you don't rely on the thread-safety of local statics.

这篇关于静态初始化时访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆