Как и все остальные, основной ответ на ваш вопрос: «Да, вы уязвимы для переполнения буфера».
В C99 вы можете использовать VLA:
void ircsocket_print(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = vsnprintf(0, 0, message, args);
va_end(args);
char buffer[len+1];
va_start(args, fmt);
int len = vsnprintf(buffer, len+1, message, args);
va_end(args);
send(ircsocket_connection, buffer, len, 0);
}
Обратите внимание на идиому, которая вызывает vsnprintf()
один раз с длиной 0 (второй ноль), чтобы получить требуемую длину, а затем вызывает ее во второй раз для форматирования данных в буфер.Также обратите внимание на тщательный сброс args
после каждого вызова на vsnprintf()
;что требуется стандартом C:
§7.15 <stdarg.h>
Если требуется доступ к переменным аргументам, вызываемая функция должна объявить объект (обычно называемый ap
в этом подпункте) типа va_list
.Объект ap
может быть передан в качестве аргумента другой функции;если эта функция вызывает макрос va_arg
с параметром ap
, значение ap
в вызывающей функции является неопределенным и должно быть передано макросу va_end
перед любой дальнейшей ссылкой на ap
.
Одним из недостатков этой формулировки является то, что она принимает пессимистический взгляд и безоговорочно вызывает vsnprintf()
дважды.Вы можете предпочесть оптимистичный подход (в большинстве случаев достаточно 512) и выделять больше места только в том случае, если первый вызов показывает, что этого недостаточно.
Еще один недостаток использования VLAнапример, если у вас не хватает места для локальной переменной buffer
, ваш код может никогда не получить возможности для восстановления.Вы должны судить, насколько это серьезная проблема.Если это проблема, используйте вместо этого явное выделение памяти (malloc()
):
char buffer = malloc(len+1);
if (buffer == 0)
return; // Report error?
...second vsnprintf() and send()...
free(buffer);
Поскольку ваша функция когда-либо возвращала только константу 1
, нет очевидной причины делать ее функцией, возвращающей что-либо- если это функция, возвращающая void
, вызывающему коду не требуется проверка возвращаемого значения.OTOH, может быть, вы должны возвращать результат вызова send()
(и, возможно, сообщение об ошибке, если malloc()
не удается).
Я также сделал параметр формата (сообщения) в const char *
;ни эта функция, ни те, которые она вызывает, не изменяют строку формата.