6

我正在尝试更新一些“遗留”代码以符合 MSVC 的最新安全更新,并且在_vsnprintf_vsnprintf_s.

特别是,我_vsnprintf使用空缓冲区和计数/长度为零进行调用,获取结果,分配所需大小的缓冲区(return value + 1),然后_vsnprintf使用新分配的缓冲区和已知正确的大小再次调用:

size_t length = _vsntprintf(nullptr, 0, mask, params);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf(final, length + 1, mask, params);

此行为记录在 MSDN 上

如果由 count 指定的缓冲区大小不足以包含由 format 和 argptr 指定的输出,则 vsnprintf 的返回值是在 count 足够大的情况下将写入的字符数。如果返回值大于 count - 1,则输出已被截断。

我正在尝试对 做同样的事情_vsnprintf_s,但它的文档不包含相同的. 相反,它说

如果存储数据所需的存储空间和终止 null 超过 sizeOfBuffer,则调用无效的参数处理程序,如参数验证中所述,除非 count 为 _TRUNCATE,在这种情况下,写入缓冲区的尽可能多的字符串,并且 - 1返回。

无论如何尝试以下方法:

size_t length = _vsntprintf_s(nullptr, 0, 0, mask, params);

这导致“长度”为零。如果您传入_TRUNCATE(-1) 作为计数,则以下断言将失败:

表达式:buffer != nullptr && buffer_count > 0

我认为可以覆盖_set_invalid_parameter_handler并以某种方式找出长度应该是多少,但是必须有一种更简单的方法吗?

4

2 回答 2

8
size_t length = _vscprintf(mask, va_list);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list);
于 2016-03-23T22:42:28.533 回答
-1

如何滚动您自己的vsnprintf不“违反规则”的变体以获得长度:

int
printf_size(const char *fmt,int count,va_list ap)
{
    char buf[2000000];
    int len;

    len = vsnprintf_s(buf,sizeof(buf),count,fmt,ap);

    return len;
}

因为返回的[最有可能]比sizeof(buf)你应该没问题。

或者,执行:

int
printf_size(const char *fmt,int count,va_list ap)
{
    char *buf;
    int siz;
    int len;

    for (siz = 2000000;  ;  siz <<= 1) {
        buf = malloc(siz);
        len = vsnprintf_s(buf,siz,count,fmt,ap);
        free(buf);
        if (len < siz)
            break;
    }

    return len;
}

或者,做一个一站式的功能:

int
sprintf_secure(char **buf,const char *fmt,int count,va_list ap)
{
    char *bp;
    int siz;
    int len;

    for (siz = 2000000;  ;  siz <<= 1) {
        bp = malloc(siz);
        len = vsnprintf_s(bp,siz,count,fmt,ap);
        if (len < siz)
            break;
    }

    bp = realloc(bp,len + 1);

    *buf = bp;

    return len;
}
于 2016-03-23T23:00:16.827 回答