Русская Википедия:Gets

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Шаблон:Lowercase 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, защитная страница может помочь с обработкой ошибок.

Примечания

Шаблон:Примечания

Ссылки

  1. Шаблон:Cite web
  2. Шаблон:Cite web
  3. Шаблон:Man — «Никогда не используйте gets(). Так как невозможно сказать, не зная ничего о данных, сколько символов будет прочитано gets(), и поэтому gets() продолжит помещать символы в буфер и после его заполнения, что весьма опасно в использовании. Это способно нарушить информационную защиту компьютерной системы.»