“ucrtbase.dll”中的 _snprintf_s() 崩溃,状态为 STATUS_ILLEGAL_INSTRUCTION
Posted
技术标签:
【中文标题】“ucrtbase.dll”中的 _snprintf_s() 崩溃,状态为 STATUS_ILLEGAL_INSTRUCTION【英文标题】:Crash in _snprintf_s() in "ucrtbase.dll" with STATUS_ILLEGAL_INSTRUCTION 【发布时间】:2018-08-26 11:34:44 【问题描述】:我注意到我的二进制文件将在 CPU 上崩溃没有 SSE 支持,异常代码 0xC000001D
(STATUS_ILLEGAL_INSTRUCTION),尽管我使用选项 /arch:IA32
进行编译。而且我已经能够追踪到它崩溃的确切位置:第一次调用 _snprintf_s()
时,它就会崩溃。崩溃发生在 ucrtbase.dll 内部,不是我自己的代码。
现在,有趣部分是,当我使用编译器选项 /MT
进行“完全静态”构建时,以避免显式依赖 ucrtbase.dll,生成的二进制文件就可以了!但是,一旦我使用选项 /MD
将某些代码编译为“共享”构建,它将在 ucrtbase.dll 中再次崩溃。
所以看起来 UCRT 的“静态”版本仍然可以在 CPU 上运行 SSE 支持,但是“共享" (DLL) 版本可以。这种不一致对我来说显然是个错误!
有什么想法吗?
构建环境:
Windows 10 v1803 Visual Studio 2017.8 (v15.8.1) Windows SDK v10.0.17134.12 工具集:v141_xp
编译器选项:/arch:IA32
测试机(仅用于兼容性测试):
CPU:奔腾 II 操作系统:带有 Service-Pack 3 的 Windows XP注意: 用于设置“共享”构建的 Redist DLL (ucrtbase.dll
+api-ms-win-*.dll
) 已直接从 C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86
目录复制!据我所知,这是这些 DLL 的最新可用版本 (v10.0.17134.12)。
即使是这个最小的测试程序也会重现崩溃:
#include <stdio.h>
int main()
char buffer[128];
_snprintf_s(buffer, 128, _TRUNCATE, "Hello %s!\n", "World!");
fputs(buffer, stdout);
getc(stdin);
return 0;
【问题讨论】:
我已经用调试器追踪了。它在_snprintf_s()
的实现内部崩溃,在系统 DLL ucrtbase.dll
内部崩溃。代码是 STATUS_ILLEGAL_INSTRUCTION,所以几乎可以肯定 不是我的代码中的问题,而是在系统 DLL ucrtbase.dll
内的预先存在的代码中使用 SSE 指令。即使是带有 nothing 但 main()
调用 _snprintf_s()
的最小测试应用程序也会重现崩溃!并且仅在 CPU 没有 SSE 上;否则它工作正常!
你试过standard snprintf()
吗?如果你可以使用 C++11,它是可用的。
您也应该将此情况报告给 Microsoft。
@KhouriGiordano 他们可能会告诉 OP,Windows XP 支持已于 2014 年结束,并且什么也不做。截至今天,所有受支持的 Windows 版本(即 8.1 和 10)都需要 SSE。
@SkepticalEmpiricist:调用snprintf()
会导致与调用_snprintf_s()
相同的崩溃。查看调用堆栈,似乎它们都在 ucrtbase.dll
内部名为 _stdio_common_vsprintf
的同一个内部例程中结束 - 它崩溃了。
【参考方案1】:
更新:
经过更多调试和摆弄,我做了一个非常有趣的观察:最新 vcredist_x86.exe
(Microsoft Visual C++ 2017) 中包含的 UCRT“Redist”DLL Redistributable installer),即 VS2017.8 (v14.15.26706) 附带的版本,实际上与 latest 的Redist\ucrt\DLLs\x86
目录中的那些 UCRT "Redist" DLL 完全不同Windows SDK (v10.0.17134.12):
ucrtbase.dll
来自 最新 Windows SDK
v10.0.17134.12
ucrtbase.dll
来自 最新 Visual C++ 2017 可再发行安装程序:
v10.0.10586.15
确实,我现在可以确认使用 最新 Visual C++ 2017 (v14.15.26706) 编译并使用 /MD
选项编译的应用程序在 non-SSE CPU,只要我们使用“旧”ucrtbase.dll
版本,从最新 vcredist_x86.exe
安装程序。
如果 Windows SDK 已经提供了更新的版本,我有点担心使用这种旧版本的 UCRT。但是,显然,这就是微软使用 Visual C++ 2017 Redistributable 安装程序所做的事情。所以,我想,这是我们应该使用的......
以防万一微软的任何人正在阅读此内容:
如果在 Windows SDK 的 Redist\ucrt
目录中,有单独的子UCRT 的每个“化身”的文件夹——UCRT 的最新“尖端”版本和我们实际上应该重新分发的 UCRT 的“兼容”版本。如果那么微软的某个人花了三分钟时间编写一个小的 README 文件,告诉我们应该选择 CRT 的哪个“化身”并将其放在Redist\ucrt\README.txt
,几乎不可能出错...
【讨论】:
从 VS 可再发行组件中提取文件并不是很简单。有关使用 WiX 工具集的过程,请参阅此 answer以上是关于“ucrtbase.dll”中的 _snprintf_s() 崩溃,状态为 STATUS_ILLEGAL_INSTRUCTION的主要内容,如果未能解决你的问题,请参考以下文章
Python 使用pyinstaller打包程序失败提示找不到c盘的某个dll文件解决方法,FileNotFoundError: [WinError 2] 系统找不到指定的文件
Python 使用pyinstaller打包程序失败提示找不到c盘的某个dll文件解决方法,FileNotFoundError: [WinError 2] 系统找不到指定的文件