2016-03-23 4 views
3

Я пытаюсь обновить некоторый «устаревший» код, чтобы соответствовать последним обновлениям безопасности для MSVC, и столкнулся с некоторыми проблемами миграции от _vsnprintf до _vsnprintf_s.Получение необходимой длины буфера с помощью защищенного _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); 

Такое поведение является documented on MSDN:

Если размер буфера задается кол не является достаточно большим, чтобы содержать выход, определенный формат и argptr, тем возвращаемое значение vsnprintf - это количество символов, которое было бы записано, если количество было достаточно большим. Если возвращаемое значение больше, чем count - 1, выход был усечен.

Я пытаюсь сделать то же самое с _vsnprintf_s, но its documentation does not contain the same. Вместо этого он говорит

Если хранилище требуется для хранения данных и нуль-терминатор превышает sizeOfBuffer, инвалиду обработчик параметров вызывается, как описано в параметре санкционирования, если счетчик не _TRUNCATE, в этом случае, как большая часть строки как вписывается в буфер, записывается и возвращается -1.

Попытка это в любом случае со следующим:

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

Это приводит к "длине" нуля. Если вы передаете в _TRUNCATE (-1), как граф вместо этого, следующее утверждение не:

Expression: буфер = nullptr & & buffer_count> 0

Я полагаю, что можно переопределить _set_invalid_parameter_handler и как-то узнать, какая длина должна быть, но должен быть более простой способ?

+0

Это не код C. – Olaf

+0

@Olaf Извините, это должно было быть C++. Я беспокоился о теге «security-enhance-crt», который я пропустил опечатку. Вы действительно думаете, что это стоило бы вниз, хотя? –

+0

В строке 'size_t length = _vsntprintf (nullptr, 0, 0, mask, params);', вы имели в виду '_vsntprintf_s'? – TriskalJM

ответ

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

Это прекрасно. Хорошее, чистое решение. '_vscprintf' должен быть задокументирован на странице' _vsnprintf_s', imho. –

-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; 
} 
+0

Благодарим за предложение, но случайным образом выделяя 4MiB данных каждый раз, когда кто-то вызывает мою функцию, является излишним. –

+0

Ну, просто используйте [первую] версию стека. Там нет выделения. С буфером 2 МБ [10 000 должно быть много], он не должен превышать максимальный предел стека. Или sprintf_secure, но начинайте с 1000 (или 100) - это параметр настройки, который можно настроить динамически, наблюдая фактическую длину используемой. Кстати, на основе вашего комментария, я просто предположил, что '* cprintf' будет непригодным для использования по тем же причинам, иначе я, вероятно, не отправил бы ответ. –

+0

Нет, защищенные функции crt заменяют только операции, связанные с записью в предварительно выделенный буфер. Не будет затронута функция типа vscprintf, которая возвращает целое число. –

Смежные вопросы