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