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