Получение требуемой длины буфера с безопасным _vsnprintf_s

Я пытаюсь обновить «устаревший» код, чтобы он соответствовал последним обновлениям безопасности для 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 и как-то выяснить, какой должна быть длина, но должен ли быть более простой способ?

4

Решение

size_t length = _vscprintf(mask, va_list);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list);
7

Другие решения

Как насчет проката собственного 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;
}
-1

По вопросам рекламы [email protected]