_vsnprintf和_vsnprintf_s的格式字符串中的可用百分比字符

free percent character in format string for _vsnprintf and _vsnprintf_s

本文关键字:vsnprintf 百分比 字符 格式 字符串      更新时间:2023-10-16

格式字符串中有空闲的"%",这是非常令人惊讶的行为。

#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;
}

这不是你期望得到的,尤其是当微软声明以下内容时

如果百分号后面跟一个字符,该字符作为format字段,则该字符将被复制到输出中而不发生更改。

那么我们在这里看到了什么?虫子?从什么时候开始?它是为msvc12/13修复的吗?

第01版:好的,我误读了声明,让我们关注崩溃的

#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;
}

第02版:
从Microsoft Connect得到答案

感谢您就此问题与Microsoft联系。我们发现忽略了有关安全函数行为的重要信息从"格式规范语法"页。安全功能对格式字符串进行额外验证,并调用无效的参数处理程序,如果初始%后面有意外字符性格默认情况下,这会终止带有Dr.Watson的程序汇报在调试模式下,它首先导致断言。更多信息位于的"参数验证"主题中https://msdn.microsoft.com/en-us/library/ksazx244.aspx。格式正在使用此信息更新规范语法页。预计下周将看到Visual Studio 2013的更新页面

这实际上是一个文档错误。更正应该很快出现在格式规范语法主题中(给它一两天时间)。缺少的信息是,格式化函数的安全版本(尾部带有_s的)会对格式化字符串进行额外验证,并且会拒绝后面跟着意外字符的百分比字符。在这种情况下,它们会调用无效的参数处理程序,而非安全版本则不会。默认情况下,这将终止程序并调用Dr.Watson报告机制。

如果您试图处理任意格式的字符串问题,您可以通过调用_set_invalid_parameter_handler来自己设置无效参数处理程序,以捕获此类情况并防止崩溃。在DEBUG构建中,此格式字符串应导致无效的参数断言。CRT中安全功能下的参数验证主题提供了更多信息。