если кто-то жалуется на get(), почему бы не сделать то же самое с scanf(“%s”,…)?

StackOverflow https://stackoverflow.com/questions/2977553

Вопрос

От man gets:

Никогда не используйте get().Потому что это невозможно сказать, не зная данные заранее, сколько characters gets() будет читать, и потому что gets() будет продолжать хранить символы после конца буфера, Его крайне опасно использовать.Он был использован для взлома компьютера безопасность.Вместо этого используйте fgets().

Почти везде я вижу scanf используется таким образом, что должна возникнуть та же проблема (переполнение буфера/переполнение буфера): scanf("%s",string).Эта проблема существует в данном случае?Почему об этом нет упоминаний в scanf справочная страница?Почему gcc не предупреждает при компиляции с помощью -Wall?

пс:Я знаю, что есть способ указать в строке формата максимальную длину строки с помощью scanf:

char str[10];
scanf("%9s",str);

редактировать:Я не прошу определить, верен ли предыдущий код или нет.Мой вопрос:если scanf("%s",string) всегда неправильно, почему нет предупреждений и ничего об этом нет на странице руководства?

Это было полезно?

Решение

Ответ прост: никто не написал в GCC код, который выдавал бы это предупреждение.

Как вы заметили, предупреждение для конкретного случая "%s" (без ширины поля) вполне уместно.

Однако имейте в виду, что это касается только случая scanf(), vscanf(), fscanf() и vfscanf().Этот спецификатор формата может быть совершенно безопасен с sscanf() и vsscanf(), поэтому в этом случае предупреждение выдаваться не должно.Это означает, что вы не можете просто добавить его к существующему коду анализа «строка формата стиля сканирования»;вам придется разделить это на опции «fscanf-style-format-string» и «sscanf-style-format-string».

Я уверен, что если вы создадите патч для последней версии GCC, у него есть хорошие шансы быть принятым (и, конечно, вам также нужно будет отправить патчи для файлов заголовков glibc).

Другие советы

С использованием gets() никогда не бывает безопасным. scanf() можно безопасно использовать, как вы сказали в своем вопросе.Однако определение того, безопасно ли вы его используете, является более сложной задачей для компилятора (например,если ты звонишь scanf() в функции, где вы передаете буфер и количество символов в качестве аргументов, она не сможет этого определить);в этом случае он должен предполагать, что вы знаете, что делаете.

Когда компилятор просматривает строку форматирования scanf, он видит строку!Это при условии, что строка форматирования не вводится во время выполнения.Некоторые компиляторы, такие как GCC, имеют дополнительные функции для анализа строки форматирования, если она введена во время компиляции.Эта дополнительная функциональность не является всеобъемлющей, поскольку в некоторых ситуациях необходимы накладные расходы во время выполнения, что НЕТ-НЕТ для таких языков, как C.Например, можете ли вы обнаружить небезопасное использование без вставки дополнительного скрытого кода в этом случае:

char* str;
size_t size;
scanf("%z", &size);
str = malloc(size);
scanf("%9s"); // how can the compiler determine if this is a safe call?!

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

Я не уверен, почему на странице руководства scanf не упоминается вероятность переполнения буфера, но vanilla scanf не является безопасным вариантом.Довольно устаревшая ссылка - http://blogs.msdn.com/b/rsamona/archive/2005/10/24/484449.aspx показывает, что это так.Кроме того, проверьте это (не gcc, но, тем не менее, информативно) - http://blogs.msdn.com/b/parthas/archive/2006/12/06/application-crash-on-replacing-sscanf-with-sscanf-s.aspx

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top