Scanf Предупреждение Cppcheck

Cppcheck показывает следующее предупреждение для scanf:

Message: scanf without field width limits can crash with huge input data. To fix this error message add a field width specifier:
    %s => %20s
    %i => %3i

Sample program that can crash:

#include 
int main()
{
    int a;
    scanf("%i", &a);
    return 0;
}

To make it crash:
perl -e 'print "5"x2100000' | ./a.out

Я не могу свернуть эту программу, набрав "огромные входные данные". Что именно я должен был напечатать, чтобы получить этот крах? Я также не понимаю смысл последней строки в этом предупреждении:

perl -e...

Ответ 1

Последняя строка представляет собой пример команды для запуска, чтобы продемонстрировать сбой с помощью программы-примера. Это по сути заставляет perl печатать в 2.100.000 раз "5", а затем передать это в stdin программы "a.out" (которая предназначена для скомпилированной программы-примера).

Прежде всего, scanf() следует использовать только для тестирования, а не в реальных программах из-за нескольких проблем, которые он не будет обрабатывать грациозно (например, запрашивать "% i", но пользовательские входы "12345abc" ( "abc" останется в stdin и может привести к заполнению следующих входов без возможности изменить их пользователя).

Относительно этой проблемы: scanf() будет знать, что он должен читать целочисленное значение, однако он не знает, как долго это может быть. Указатель может указывать на 16-битное целое число, 32-битное целое число или 64-битное целое число или нечто большее (что не известно). Функции с переменным числом аргументов (определенные с помощью ...) не знают точного типа данных переданных элементов, поэтому он должен полагаться на строку формата (причина, по которой теги формата не являются необязательными, как на С#, где вы просто их число, например "{0} {1} {2}"). И без заданной длины он должен принять некоторую длину, которая также может быть зависимой от платформы (что делает функцию еще более неактивной для использования).

В общем, считайте, что это может быть вредным и отправной точкой для переполнения буфера. Если вы хотите защитить и оптимизировать свою программу, начните с замены ее альтернативами.

Ответ 2

Я попробовал запустить выражение perl против программы C, и он сработал здесь в Linux (ошибка сегментации).

Ответ 3

Использование функции "scanf" (или fscanf и sscanf) в реальных приложениях обычно не рекомендуется вообще, потому что оно небезопасно, и обычно это отверстие для переполнения буфера, если будут введены некорректные входные данные. Существует гораздо более безопасный способ ввода чисел во многие широко используемые библиотеки для С++ (QT, библиотеки времени выполнения для Microsoft Visual С++ и т.д.). Вероятно, вы можете найти безопасные альтернативы для "чистого" языка C.