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()
продовжить поміщати символи в буфер і після його заповнення, що дуже небезпечно у використанні. Це може порушити інформаційний захист комп'ютерної системи.»