意外的snprintf行为 我注意到(我的观点)在几个平台上用C++进行SNPrTNF非常奇怪的行为。考虑下面的代码(导致观察到的行为的最小工作示例):

意外的snprintf行为 我注意到(我的观点)在几个平台上用C++进行SNPrTNF非常奇怪的行为。考虑下面的代码(导致观察到的行为的最小工作示例):,c++,C++,因此,将test1作为参数传递给第一个%s会导致在test1数组结束后进行读取 这种行为导致windows驱动程序出现多个页面错误(是的,我知道它是静态数据…)。幸运的是,代码是可移植的,当移植到linux时,valgrind报告了该错误 但据我所知,snprintf应该在第6个字节处用\0终止test1(确实如此,检查了)。那么,为什么要在test1数组结束后读取第3条snprintf语句呢?将第三条snprintf语句更改为 snprintf(test3,sizeof(test3),“%.5

因此,将test1作为参数传递给第一个%s会导致在test1数组结束后进行读取

这种行为导致windows驱动程序出现多个页面错误(是的,我知道它是静态数据…)。幸运的是,代码是可移植的,当移植到linux时,valgrind报告了该错误

但据我所知,snprintf应该在第6个字节处用\0终止test1(确实如此,检查了)。那么,为什么要在test1数组结束后读取第3条snprintf语句呢?将第三条snprintf语句更改为

snprintf(test3,sizeof(test3),“%.512s%s”,test1,test2);
解决了两种平台上的问题。将代码编译为C代码(不是C++)不会导致错误

更新:在linux(也可能是windows)上,只有在编译代码时包含调试信息并且禁用了优化(-g-O0用于gcc)时才会发生错误。

由于全局对象(如示例中的数组)是0-初始化的,所以最后一个snprintf的读取永远不会超过字符串的结尾,与之前的sprintfs是否复制了终止的0字符无关。唯一的解释是,以前的snprintfs复制到目标
test1
的“test1”远远多于提交的“test1”,用非0覆盖所有0(顺便说一句,使用随机内存不太可能没有0)

这是不太可能的——这样一个明显的错误早就被发现了。关于驱动程序中的错误,我怀疑内存被完全不相关的“进程”覆盖(一般来说,可能是另一个驱动程序)。对于桌面应用程序,我无法解释为什么它会失败。使用GCC4.8.3在Codingground上尝试您的示例运行得很好,当我在末尾添加printf()时,输出了预期的字符串


顺便说一句,在启用优化的情况下,原始代码运行良好也就不足为奇了:因为没有明显的效果,编译器可能只会发出一个NOP。

在这种情况下,这并不意味着它会有所不同,但源文件名在valgrind输出中被称为
1.cc
。你有什么原因写C++并用C++编译器编译它吗?我只是用<代码> ValgnDe--工具= Exp SGCHECK/<代码>测试了你的代码,没有错误报告,你使用的是什么版本的<代码> Valgnnd<代码>,什么版本的代码> GLBCK</代码>,还有什么是你的Linux发行版?你能告诉我们更多吗?例如,你的平台、编译器版本、如何编译代码。@ IHAROB,你不应该得到这样的差异,SNPRETNF和原始数组在这2种语言中的行为是相同的。当C++中包含<代码> <代码>时,会发生吗?一天之前,我完全同意你的答案;但是现在我有一些崩溃转储,它们精确地指向snprintf语句,在驱动程序的静态数据部分之后直接出现一个PAGE_错误。如前所述,更改snprintf解决了这个问题。此外,崩溃直接发生在驱动程序初始化之后,因此不需要触发此错误。但我同意这里的情况非常复杂,毕竟它似乎是MSC++编译器中的一个错误。可悲的是,windows没有valgrind:(cygwin上的gcc 4.9.x以及VS 2013运行该示例很好(但windows上没有valgrind,所以我只能运行该程序)。你真的能在普通用户空间程序中重现错误吗?编辑:我编译为C,重新阅读你原来不相关的帖子;-)Edt2: VS2013作为C++也运行良好。我不能在用户空间中重现这个bug(例如,导致崩溃)。然而,在大多数情况下,它根本不会触发崩溃,因为分页内存很有可能跟随最后声明的静态数据。为了制作一个合适的测试用例,可以使用valgrind之类的工具来进一步详细说明无效读取访问是在什么情况下发生的,以及如何将其放置在未分页内存中(尊重对齐和页面大小)。但是我不能在这里透露原始代码,因为它是一个商业产品;运行时环境当然是不同的。作为一个实际问题(我相信你也想到了),至少对于字符串来说,用特殊代码替换snprintf是很简单的。这是您最初的用例吗?
#include <stdio.h>

char test1[512];
char test2[512];
char test3[1024];
char test4[1024];

int main()
{
    snprintf(test1, sizeof(test1), "test1");
    snprintf(test2, sizeof(test2), "test2");
    snprintf(test3, sizeof(test3), "%s %s", test1, test2);
    return 0;
}