Рассмотрите C-фрагмент: char *s = malloc(5);\n strcpy(s, \"Hello\");\n free(s);\n printf(\"%s\", s);\nОбъясните, почему это неопределённое поведение, какие симптомы могут проявляться и как исправить код безопасно
Проблема в двух независимых неопределённых действиях: 1) Недостаточно памяти для строки "Hello". Выделено 5 \;5\;5 байт (malloc( 5 )\text{malloc}(\;5\;)malloc(5)), а строка "Hello" имеет длину 5 \;5\;5 символов плюс завершающий нулевой байт — итого 6 \;6\;6 байт. Запись через `strcpy` переписывает границы буфера (heap buffer overflow) — это уже UB (коррупция кучи, повреждение управляющих структур, и т.п.). 2) Использование указателя после `free(s)` — use-after-free. После `free` память освобождена, чтение по `s` даёт UB (может читаться старое содержимое, мусор, вызывать сегфолт или быть используемо в атаке). Возможные симптомы - Программа печатает "Hello", мусор или пустую строку. - Случайные сбои (segfault). - Непредсказуемое поведение в других частях программы (коррупция кучи). - Уязвимость для эксплуатаций (RCE, info leak). Как исправить (безопасно) - Выделить достаточный буфер: например char *s = malloc( 6 \;6\;6); /* или */ char *s = malloc(strlen("Hello")+1)\text{malloc}(\text{strlen}("Hello") + 1)malloc(strlen("Hello")+1); - Не использовать указатель после free: сначала вывести/обработать, потом free; после free присвоить NULL для избежания случайного повторного использования: free(s); s = NULL; - Альтернативы с меньшим шансом ошибки: - Использовать strdup: char *s = strdup("Hello"); /* затем free(s) */. - Использовать функции, явно ограничивающие размер: snprintf, memcpy с известной длиной или платформенную strlcpy. - Проверять результат malloc (на NULL) при необходимости. Пример исправленного кода: char *s = malloc(strlen("Hello")+1\text{strlen}("Hello") + 1strlen("Hello")+1); if (s) { strcpy(s, "Hello"); printf("%s", s); free(s); s = NULL; }
1) Недостаточно памяти для строки "Hello". Выделено 5 \;5\;5 байт (malloc( 5 )\text{malloc}(\;5\;)malloc(5)), а строка "Hello" имеет длину 5 \;5\;5 символов плюс завершающий нулевой байт — итого 6 \;6\;6 байт. Запись через `strcpy` переписывает границы буфера (heap buffer overflow) — это уже UB (коррупция кучи, повреждение управляющих структур, и т.п.).
2) Использование указателя после `free(s)` — use-after-free. После `free` память освобождена, чтение по `s` даёт UB (может читаться старое содержимое, мусор, вызывать сегфолт или быть используемо в атаке).
Возможные симптомы
- Программа печатает "Hello", мусор или пустую строку.
- Случайные сбои (segfault).
- Непредсказуемое поведение в других частях программы (коррупция кучи).
- Уязвимость для эксплуатаций (RCE, info leak).
Как исправить (безопасно)
- Выделить достаточный буфер: например
char *s = malloc( 6 \;6\;6); /* или */ char *s = malloc(strlen("Hello")+1)\text{malloc}(\text{strlen}("Hello") + 1)malloc(strlen("Hello")+1);
- Не использовать указатель после free: сначала вывести/обработать, потом free; после free присвоить NULL для избежания случайного повторного использования:
free(s);
s = NULL;
- Альтернативы с меньшим шансом ошибки:
- Использовать strdup: char *s = strdup("Hello"); /* затем free(s) */.
- Использовать функции, явно ограничивающие размер: snprintf, memcpy с известной длиной или платформенную strlcpy.
- Проверять результат malloc (на NULL) при необходимости.
Пример исправленного кода:
char *s = malloc(strlen("Hello")+1\text{strlen}("Hello") + 1strlen("Hello")+1);
if (s) {
strcpy(s, "Hello");
printf("%s", s);
free(s);
s = NULL;
}