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, захисна сторінка може допомогти з обробкою помилок.

Примітки[ред. | ред. код]

  1. GNU. GNU Библиотека Си — Строковый Ввод. Архів оригіналу за 19 березня 2012. Процитовано 2 серпня 2008. Функція gets дуже небезпечна, оскільки вона не забезпечує жодного захисту від переповнення рядка s. Бібліотека GNU включає її тільки заради сумісності. Вам слід завжди використовувати замість неї fgets або getline.
  2. Чому всі кажуть не використовувати gets()?. comp.lang.c Часті питання. Архів оригіналу за 19 березня 2012. Процитовано 2 серпня 2008.(англ.)
  3. gets(3) [Архівовано 24 березня 2022 у Wayback Machine.] — «Ніколи не використовуйте gets(). Оскільки неможливо сказати, не знаючи нічого про дані, скільки символів прочитає gets(), і тому gets() продовжить поміщати символи в буфер і після його заповнення, що дуже небезпечно у використанні. Це може порушити інформаційний захист комп'ютерної системи.»

Посилання[ред. | ред. код]

  • gets. pubs.opengroup.org. Архів оригіналу за 21 січня 2022. Процитовано 30 березня 2022.