【发布时间】:2015-05-20 19:44:47
【问题描述】:
格式字符串中的免费“%”行为非常令人惊讶。
#include <iostream>
#include <stdarg.h>
#include <stdio.h>
void foo(const char *format, ...) {
const size_t buffSize = 1024;
char msg[buffSize];
{
va_list args;
va_start(args, format);
_vsnprintf(msg, buffSize, format, args);
va_end(args);
std::cout << msg << std::endl; // here you get a,b,,c,d,e
}
{
va_list args;
va_start(args, format);
_vsnprintf_s(msg, buffSize, format, args); // and here you crash and burn
va_end(args);
std::cout << msg << std::endl;
}
}
int _tmain(int argc, _TCHAR *argv[]) {
foo("%s,b,%,c,d,%s", "a", "e");
return 0;
}
这不是你期望得到的,尤其是当下面的is stated by Microsoft
如果百分号后面跟着一个没有意义的字符 格式字段,字符被复制到输出不变。
那么我们在这里看到了什么?一个错误?从何时起?是否为 msvc12/13 修复了?
EDIT01: 好的,我看错了声明,让我们专注于崩溃
#include <iostream>
#include <stdarg.h>
#include <stdio.h>
void foo(const char *format, ...) {
const size_t buffSize = 1024;
char msg[buffSize];
va_list args;
va_start(args, format);
_vsnprintf_s(msg, buffSize, format, args);
va_end(args);
std::cout << msg << std::endl;
}
int main(int argc, char *argv[]) {
foo("b,%,c,d"); // crash here
foo("%s,b,%,c,d,%s", "a", "e"); // there and everywhere
return 0;
}
EDIT02:
从 Microsoft Connect 获得答案
感谢您就此问题与 Microsoft 联系。我们发现我们 遗漏了有关安全功能如何表现的重要信息 从格式规范语法页面。安全功能 格式字符串的附加验证,并调用无效的 如果在初始 % 之后出现意外字符,则参数处理程序 特点。默认情况下,这会使用 Dr. Watson 终止程序 报告。在调试模式下,它首先导致断言。更多信息是 在参数验证主题中可用 https://msdn.microsoft.com/en-us/library/ksazx244.aspx 。格式 正在使用此信息更新规范语法页面。 预计在下周看到 Visual Studio 2013 的更新页面 左右。
【问题讨论】:
-
有什么问题?字符 (
',') 被 原样复制到输出。如果要打印实际的百分号,请将其加倍:"%%"。不知道关于坠机的事。不确定您是否可以像这样重用参数列表。 -
该死!我误读了声明......安全功能崩溃怎么办?想法?
-
如果您希望
%可靠地出现在输出中,请在格式字符串中使用%%。%,c字符串可以解释为带有未知修饰符(标志)的%c;这可能意味着最后的%s正在读取垃圾,然后崩溃。不要依赖未定义的行为。 -
即使你不重复使用它也会崩溃
-
@JonathanLeffler 至于你的第一条评论 - 当格式字符串是免费的运行时字符串时,你如何管理你的双百分比转义,例如由用户提供,不,我不想构建格式验证器 :) 你能详细说明你的第二条评论吗?
标签: c++ visual-studio-2012 printf