_vsnprintf和_vsnprintf_s的格式字符串中的空闲百分比字符

时间:2015-04-21 19:14:08

标签: c++ visual-studio-2012 printf

格式字符串中的免费'%'非常令人惊讶。

#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

  

如果百分号后跟一个没有意义的字符   格式字段,字符被复制到输出不变。

那么我们在这里看到了什么?一个bug?从何时起?它是固定的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的更新页面   左右。

1 个答案:

答案 0 :(得分:2)

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

如果您正在尝试处理任意格式字符串问题,可以通过调用_set_invalid_parameter_handler来自行设置无效参数处理程序以捕获此类情况,并防止崩溃。在DEBUG构建中,此格式字符串应导致无效的参数断言。 Parameter Validation下的Security Features in the CRT主题提供了更多信息。