Я пытаюсь обновить «устаревший» код, чтобы он соответствовал последним обновлениям безопасности для 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, недостаточно велик, чтобы вместить выходные данные, заданные форматами и argptr, возвращаемое значение vsnprintf — это количество символов, которое будет записано, если count будет достаточно большим. Если возвращаемое значение больше, чем count — 1, выходные данные были усечены.
Я пытаюсь сделать то же самое с _vsnprintf_s
, но его документация не содержит того же. Вместо этого говорится
Если объем памяти, необходимый для хранения данных, и завершающий ноль превышает sizeOfBuffer, вызывается недопустимый обработчик параметра, как описано в разделе Проверка параметров, если только счетчик не равен _TRUNCATE, в этом случае записывается столько строк, сколько уместится в буфере, и — 1 вернулся.
В любом случае, попробуйте следующее:
size_t length = _vsntprintf_s(nullptr, 0, 0, mask, params);
Это приводит к «длине» нуля. Если вы проходите в _TRUNCATE
(-1) вместо этого, следующее утверждение не выполняется:
Выражение: buffer! = Nullptr && buffer_count> 0
Я предполагаю, что можно переопределить _set_invalid_parameter_handler
и как-то выяснить, какой должна быть длина, но должен ли быть более простой способ?
size_t length = _vscprintf(mask, va_list);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list);
Как насчет проката собственного 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;
}