_vsnprintf 和 _vsnprintf_s 格式字符串中的自由百分比字符

free percent character in format string for _vsnprintf and _vsnprintf_s

格式字符串中有游离“%”的行为非常令人惊讶。

#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

If a percent sign is followed by a character that has no meaning as a format field, the character is copied to the output unchanged.

那么我们在这里看到了什么?错误?从何时起? msvc12/13 是否已修复?

编辑01: 好吧,我看错了声明,让我们专注于 crash

#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 得到了答案

Thanks for contacting Microsoft about this issue. We've found that we left out important information about how the secure functions behave from the Format Specification Syntax page. The secure functions do additional validation of the format string, and invoke the invalid parameter handler if an unexpected character follows the initial % character. By default, this terminates the program with a Dr. Watson report. In Debug mode, it causes an assert first. More information is available in the Parameter Validation topic at https://msdn.microsoft.com/en-us/library/ksazx244.aspx . The Format Specification Syntax page is being updated with this information. Expect to see the updated page for Visual Studio 2013 in the next week or so.

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

如果您尝试处理任意格式的字符串问题,您可以通过调用 _set_invalid_parameter_handler to trap cases like this, and prevent a crash. In DEBUG builds, this format string should cause an invalid parameter assertion. The Parameter Validation topic under Security Features in the CRT 自己设置无效参数处理程序以获得更多信息。