Функцией с переменным количеством аргументов (variadic функцией) называют функцию, способную принимать заранее неопределённое количество входных аргументов. Во многих языках программирования функции форматного вывода определены как variadic функции.
В С++ функции с переменным количеством аргументов объявляются с помощью многоточия (...) в списке аргументов. Компилятор осуществляет проверку типов только для явно заданных аргументов. Для доступа к переменному списку аргументов используются макросы va_arg, va_end, и va_start из заголовочного файла STDARG.H. Семейство функций printf является одним из распространённых примеров функций с переменным количеством аргументов.
В некоторых языках использование функций с переменным количеством аргументов может приводить к проблемам с безопасностью типов. Например в С/C++ функции семейства printf при неосторожном использовании могут создавать уязвимости неконтролируемого формата строки. Несоответствие строки форматирования и переданных аргументов может приводить к непредсказуемому поведению, ошибкам переполнения буфера, повреждению стека и выполнению произвольного кода, приводить к разрушению областей динамической памяти.
Хотя о подобных проблемах с variadic функциями известно уже достаточно давно, только в 1999 году они были идентифицированы как серьёзная уязвимость для безопасности. А в связи с тем, что достаточно долго подобные уязвимости считались относительно безобидными, сейчас они являются одними из самых распространённых ошибок.
Для исправления и предотвращения ошибок с использованием variadic функций можно использовать предупреждения от компилятора или сторонние статические анализаторы исходного кода. Стоит помнить, что статический анализ позволяет выявлять некорректные строки форматирования только если они известны в момент компиляции. Поэтому особую осторожность стоит проявлять в случае, если программа динамически формирует строку форматирования во время выполнения или получает её от пользователя.
Далее приведём несколько примеров ошибок использования функций с переменным количеством аргументов, найденных в известных open-source проектах с помощью статического анализатора PVS-Studio.
Проект ReactOS. Некорректная печать символа типа WCHAR.
static void REGPROC_unescape_string(WCHAR* str)
{
...
default:
fprintf(stderr,
"Warning! Unrecognized escape sequence: \\%c'\n",
str[str_idx]);
...
}
Функция fprinf() должна распечатать символ типа char. Но третьим аргументов является символ типа WCHAR. Пользователю будет выдано некорректно сформированное сообщение. Чтобы код стал корректен, в строке, задающей формат, следует заменить '%c' на '%C'.
Проект Intel AMT SDK. Неиспользуемый аргумент.
bool GetUserValues(...)
{
...
printf("Error: illegal value. Aborting.\n", tmp);
return false;
}
Ошибка в том, что переменная 'tmp' никак не используется при выводе информационного сообщения.
0