1

我最初在ReverseEngineering StackExchange上发布了这个,不知道它属于哪个位置。无论如何,我决定在这里发布它。函数本地静态生成Windows XP的错误代码

最近,Microsoft Visual Studio 2015编译器最终符合C++标准规定,为函数本地静态生成线程安全代码。在大多数情况下这工作得很好,但我遇到的情况在Windows XP在以下3个指令导致的吹胀:

mov  eax,dword ptr fs:[0000002Ch] 
mov  ecx,dword ptr [MyModule!_tls_index (102eea44)] 
mov  ecx,dword ptr [eax+ecx*4] 

显然编译器似乎先戳成TLS来实现线程安全当前线程的插槽。 fs:2Ch应该导致每个文档的TLS数组。但是在Windows XP上,似乎没有设置fs:2Ch。这对我来说返回0,下一条指令也是(_tls_index也是0)。这导致第3条指令因访问无效内存而炸毁。

有谁知道为什么fs:2Ch可能没有在Windows XP上设置?我们的代码中使用了本地静态函数,我无法想象没有其他人会遇到这种情况。

UPDATE

我已经仔细考虑我已经申请了这个问题每一个标签。请不要添加或删除任何东西。

+0

您是否在构建代码时正确定位到XP平台? –

+0

@KubaOber是的,我是。我们使用v140_xp工具集。 – ForeverLearning

+0

XP SP3上的问题是什么? –

回答

0

在C++ 11标准,阻断与静态或线程存储时限范围变量必须是零初始化任何其它初始化发生之前。当控件第一次通过变量的声明时发生初始化。如果在初始化期间抛出异常,则该变量被视为未初始化,并且在下一次控制通过声明时重新尝试初始化。如果控制与初始化同时进入声明,则在初始化完成时并发执行块。如果控制在初始化期间递归地重新输入声明,则行为是不确定的。默认情况下,从Visual Studio 2015开始的Visual Studio实现此标准行为。这种行为可以通过设置/ Zc:threadSafeInit编译器选项来显式指定。 + 静态局部变量的线程安全初始化依赖于通用C运行时库(UCRT)中实现的代码。为避免依赖于UCRT,或在Visual Studio 2015之前保留Visual Studio版本的非线程安全初始化行为,请使用/ Zc:threadSafeInit-选项。如果您知道不需要线程安全性,那么使用此选项可在静态本地声明周围生成更小,更快的代码。 线程安全的静态局部变量在内部使用线程本地存储(TLS)来提供静态初始化时的高效执行。此功能的实施依赖于Windows Vista和更高版本操作系统中的Windows操作系统支持功能。 Windows XP,Windows Server 2003和更早版本的操作系统没有这种支持,所以它们没有获得效率优势。这些操作系统对可加载的TLS部分的数量也有一个下限。超过TLS部分的限制可能会导致崩溃。如果这是代码中的问题,尤其是在必须在较早的操作系统上运行的代码中,请使用/ Zc:threadSafeInit来禁用线程安全的初始化代码。

+0

您可能要有点格式化文本目前,它是文本人的区区墙想得解码。 – mkl