Рассмотрите фрагмент на C:
char *bad() { char buf[8]; strcpy(buf, "This is long"); return buf; }
Объясните проблему, последствия и варианты исправления

18 Ноя в 10:11
3 +2
0
Ответы
1
Проблема:
- В функции есть два независимых дефекта: локальный массив `buf` размером \(\(8\)\) и копирование в него строки `"This is long"` длиной \(\(12\)\) символов (без\0) — с терминатором выходит \(\(13\)\) байт. Фактически выполняется переполнение буфера на \(\(5\)\) байт, и одновременно возвращается указатель на стековую память (локальный массив), которая после выхода из функции недействительна (dangling pointer).
Последствия:
- Переполнение буфера приводит к переписыванию соседних областей памяти — возможен крах программы, corrupted return address, перезапись локальных переменных и т.п.
- Возврат указателя на локальную память — неопределённое поведение при использовании результата: чтение/запись по этому указателю может привести к аварии или к уязвимости безопасности.
- В сумме это потенциально критическая уязвимость: удалённое выполнение кода, эскалация прав или просто немедленный крах.
Варианты исправления (коротко, с преимуществами и недостатками):
1) Выделять динамическую память (caller должен освобождать):
- Пример: выделить `malloc(strlen(s)+1)` или использовать `strdup`.
- Плюс: безопасно и гибко. Минус: ответственность за `free`.
2) Попросить вызывающего предоставить буфер:
- Функция принимает `char *buf, size_t bufsize` и пишет ограниченно (`snprintf`, `strlcpy`, `strncpy` с ручной терминацией).
- Плюс: нет внутреннего аллока; управление размером у вызывающего. Минус: обязан контролировать размеры.
3) Использовать статическое или статически инициализированное хранилище:
- `static char buf[] = "This is long";`
- Плюс: просто вернуть безопасно. Минус: не потокобезопасно для записи, одна копия для всех вызовов.
4) Вернуть структуру по значению, содержащую массив нужного размера:
- Плюс: безопасно, без динамики. Минус: может быть громоздко при больших буферах.
5) Увеличить буфер и использовать безопасные функции:
- Если действительно нужно помещать эту строку в локальный буфер, установить размер не меньше \(\(13\)\) (для данной строки) и использовать `snprintf`/`strlcpy`.
- Но даже при увеличении нельзя возвращать адрес локальной памяти — этот пункт решает только переполнение, не проблему возврата.
Рекомендуемое исправление (вариант с malloc):
- Код:
char *good(void) {
const char *s = "This is long";
char *buf = malloc(strlen(s) + 1);
if (!buf) return NULL;
strcpy(buf, s);
return buf;
}
// Вызывать и затем free().
Краткое резюме:
- Исправьте оба дефекта: избегайте переполнения (проверка размеров / безопасные API) и не возвращайте указатель на локальную стековую память (используйте динамику, статическое хранилище, буфер от вызывающего или возврат struct).
18 Ноя в 10:18
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир