gets
gets
— функция, входящая в Стандартную библиотеку языка Си, объявляемая в заголовочном файле stdio.h
, которая считывает строку стандартного ввода и помещает её в буфер, созданный вызывающей функцией. Если выдаёт ошибку, то теперь для её вызова следует использовать gets_s.
Реализация
Может быть реализована следующим способом (при помощи getchar
):
char *gets(char *s)
{
/*очистка буфера ввода */
fflush(stdin);
int i, k = getchar();
/* Возвращаем NULL если ничего не введено */
if (k == EOF)
return NULL;
/* Считываем и копируем в буфер символы пока не достигнем конца строки или файла */
for (i = 0; k != EOF && k != '\n'; ++i) {
s[i] = k;
k = getchar();
/* При обнаружении ошибки результирующий буфер непригоден */
if (k == EOF && !feof(stdin))
return NULL;
}
/* Нуль-терминируем и возвращаем буфер в случае успеха.
Символ перевода строки в буфере не хранится. */
s[i] = '\0';
return s;
}
Программист должен знать максимум числа символов, которые должны быть считаны gets
, чтобы удостовериться, что выделяется буфер достаточного размера. Подобное невозможно без информации о данных. Эта проблема может приводить к созданию ошибок и открывает простор для нарушений компьютерной безопасности при помощи переполнения буфера. Многие источники советуют программистам никогда не использовать gets
в новых программах[1][2][3].
Применение gets
весьма осуждается. Функция оставлена в стандартах C89 и C99 для обратной совместимости. Множество инструментов разработки ПО, как, например, GNU ld, выдаёт предупреждения в случае обнаружения при компоновке кода с использованием gets
.
Альтернативы
Вместо gets
могут быть использованы другие функции строкового ввода, что позволит избежать ошибок, связанных с переполнением буфера. Простейшим вариантом будет fgets
. При замене кода вида
char buffer[BUFFERSIZE];
gets(buffer);
кодом вида
char buffer[BUFFERSIZE];
fgets(buffer, sizeof(buffer), stdin);
нужно иметь в виду, что вызов fgets(buffer, sizeof buffer, stdin)
отличается от gets(buffer)
не только защитой от переполнения буфера, но и тем, что fgets(buffer, sizeof buffer, stdin)
сохраняет завершающий символ перевода строки (если ввод линии заканчивается символом перевода строки), в то время как gets(buffer)
отбрасывает его.
Безопасность использования
Безопасное использование gets
требует от программиста проверки того, что переполнение буфера не станет проблемой. Стандарт языка Си этого не гарантирует; тем не менее, существует несколько относительно усложненных способов проверки этого с различной степенью переносимости. Одним из возможных вариантов является защитная страница для защиты памяти. В сочетании с обработчиками исключений, такими как SIGSEGV
и sigaction
, защитная страница может помочь с обработкой ошибок.
Примечания
- GNU. GNU Библиотека Си — Строковый Ввод (недоступная ссылка). — «Функция
gets
весьма опасна, так как она не обеспечивает никакой защиты от переполнения строкиs
. Библиотека GNU включает её только ради совместимости. Вам следует всегда использовать вместо неёfgets
илиgetline
.». Дата обращения: 2 августа 2008. Архивировано 19 марта 2012 года. - Почему все говорят не использовать
gets()
? (недоступная ссылка). comp.lang.c Часто Задаваемые Вопросы. Дата обращения: 2 августа 2008. Архивировано 19 марта 2012 года. -
gets(3)
— страница справки man по библиотечным функциям GNU/Linux (англ.) — «Никогда не используйтеgets()
. Так как невозможно сказать, не зная ничего о данных, сколько символов будет прочитаноgets()
, и поэтомуgets()
продолжит помещать символы в буфер и после его заполнения, что весьма опасно в использовании. Это способно нарушить информационную защиту компьютерной системы.»
Ссылки
gets
— системные интерфейсы, The Single UNIX® Specification, выпуск 7 от The Open Group (англ.)