Дан фрагмент на C: "char *s = malloc(10); strcpy(s, \"This is a very long string\");" Объясните, что происходит, какие последствия и как это безопасно исправить
Кратко — что происходит - Вызывается `malloc(101010)`: выделяется буфер на куче размером 101010 байт. - `strcpy(s, "This is a very long string");` копирует содержимое строки длиной 262626 символов плюс терминатор `\0`, итого 272727 байт, в буфер размером 101010. Происходит переполнение буфера (buffer overflow). Последствия - Некорректное поведение программы — аварийный завершение, зависания. - Порча данных в памяти (коррупция кучи, соседних объектов). - Уязвимость для эксплуатации (исполнение произвольного кода, утечки данных). - Поведение неопределено (UB) — результат непредсказуем. Как безопасно исправить (короткие варианты) 1) Выделять ровно столько, сколько нужно: - вычислить размер и выделить: char *src = "This is a very long string"; size_t need = strlen(src) + 111; char *s = malloc(need); if (!s) { /* обработать ошибку */ } strcpy(s, src); Здесь `need = strlen(src) + 111` учитывает нулевой терминатор. 2) Использовать strdup (удобно, но требует проверку NULL и освобождение): char *s = strdup(src); /* выделяет strlen(src) + 111 байт */ 3) Использовать безопасные копирующие функции, задавая предел: size_t need = strlen(src) + 111; char *s = malloc(need); if (s) strlcpy(s, src, need); /* или snprintf(s, need, "%s", src); */ 4) Если копируете литерал и знаете длину, выделить явно: char *s = malloc(272727); /* 262626 символов + 111 для '\0' */ strcpy(s, "This is a very long string"); Что не рекомендуется - Использовать `strncpy` без тщательной обработки — она не гарантирует нуль-терминатор при усечении и может оставить буфер незаполненным. - Игнорировать проверку возвращаемого значения `malloc`. Дополнительно - Всегда проверяйте результат `malloc` на NULL. - Помните освобождать память (`free(s)`) когда она больше не нужна.
- Вызывается `malloc(101010)`: выделяется буфер на куче размером 101010 байт.
- `strcpy(s, "This is a very long string");` копирует содержимое строки длиной 262626 символов плюс терминатор `\0`, итого 272727 байт, в буфер размером 101010. Происходит переполнение буфера (buffer overflow).
Последствия
- Некорректное поведение программы — аварийный завершение, зависания.
- Порча данных в памяти (коррупция кучи, соседних объектов).
- Уязвимость для эксплуатации (исполнение произвольного кода, утечки данных).
- Поведение неопределено (UB) — результат непредсказуем.
Как безопасно исправить (короткие варианты)
1) Выделять ровно столько, сколько нужно:
- вычислить размер и выделить:
char *src = "This is a very long string";
size_t need = strlen(src) + 111;
char *s = malloc(need);
if (!s) { /* обработать ошибку */ }
strcpy(s, src);
Здесь `need = strlen(src) + 111` учитывает нулевой терминатор.
2) Использовать strdup (удобно, но требует проверку NULL и освобождение):
char *s = strdup(src); /* выделяет strlen(src) + 111 байт */
3) Использовать безопасные копирующие функции, задавая предел:
size_t need = strlen(src) + 111;
char *s = malloc(need);
if (s) strlcpy(s, src, need); /* или snprintf(s, need, "%s", src); */
4) Если копируете литерал и знаете длину, выделить явно:
char *s = malloc(272727); /* 262626 символов + 111 для '\0' */
strcpy(s, "This is a very long string");
Что не рекомендуется
- Использовать `strncpy` без тщательной обработки — она не гарантирует нуль-терминатор при усечении и может оставить буфер незаполненным.
- Игнорировать проверку возвращаемого значения `malloc`.
Дополнительно
- Всегда проверяйте результат `malloc` на NULL.
- Помните освобождать память (`free(s)`) когда она больше не нужна.