Дан код на C: char *s = malloc(10); strcpy(s, "This is a very long string"); free(s); printf("%s", s); — проанализируйте ошибки, связанные с управлением памятью, возможные последствия в рантайме и подходы к безопасному управлению памятью в C и в более современных языках

12 Окт в 14:18
2 +1
0
Ответы
1

Код
char *s = malloc101010;
strcpy(s, "This is a very long string");
freesss;
printf("%s", s);
содержит несколько серьёзных ошибок работы с памятью и приводит к неопределённому поведению. Разберём по пунктам.

1) Переполнение буфера bufferoverflowbuffer overflowbufferoverflow

Вы выделяете 10 байт, а копируете строку значительно большей длины. strcpy не проверяет границы и запишет байты за пределами выделенной области, что приводит к повреждению кучи/смежных данных.Последствия: крах программы segfaultsegfaultsegfault, повреждение управляющих структур аллокатора можетпривестикдальнейшимошибкамприmalloc/freeможет привести к дальнейшим ошибкам при malloc/freeможетпривестикдальнейшимошибкамприmalloc/free, утечка данных, эксплуатация уязвимости разрешениепроизвольноговыполнениякодаразрешение произвольного выполнения кодаразрешениепроизвольноговыполнениякода.

2) Use-after-free использованиеосвобождённойпамятииспользование освобождённой памятииспользованиеосвобождённойпамяти

Вы освобождаете s через freesss, а затем используете его в printf. После free указатель становится висячим — чтение по нему даёт неопределённое поведение: может вывести старые данные, мусор, вызвать сегфолт или ничего не вывести. Нельзя полагаться на наблюдаемое поведение — это UB.

3) Отсутствие проверки результата malloc

Если malloc вернёт NULL, дальнейшее strcpy приведёт к дереференсу NULL и немедленному падению.

Что может случиться в рантайме

Немедленный сегфолт при записи/чтении;Краш при последующих аллокациях/освобождениях из−заповреждённойкучииз-за повреждённой кучииззаповреждённойкучи;Неожиданное поведение у разных компиляторов/платформ — UB не определено;Возможность эксплойта heapoverflow→перезаписьметаданных→выполнениепроизвольногокодаheap overflow → перезапись метаданных → выполнение произвольного кодаheapoverflowперезаписьметаданныхвыполнениепроизвольногокода.

Как безопасно работать в C

Выделяйте ровно столько, сколько нужно: size_t len = strlensrcsrcsrc + 1; s = malloclenlenlen;Проверяйте результат malloc: if !s!s!s { / обработка ошибки / }Не используйте strcpy для непроверенных данных. Предпочтения:
strdup еслидоступнаесли доступнаеслидоступна: s = strdupsrcsrcsrc; проверка на NULL;snprintf/memcpy, memcpy/strlen при заранее вычисленной длине;strlcpy еслидоступнанаплатформеесли доступна на платформееслидоступнанаплатформе вместо strncpy;asprintf GNUGNUGNU для форматируемых строк.Если используете strncpy, помните о нюансах (может не дописать '\0'); лучше явно гарантировать нуль-терминатор.Не используйте указатель после free. Если нужно ещё работать со строкой — выводите до free или делайте копию.После free ставьте ptr = NULL, чтобы последующее освобождение/использование легче выявлялось NULLderef—явныйcrash,прощеотладитьNULL deref — явный crash, проще отладитьNULLderefявныйcrash,прощеотладить.Для отладки используйте инструменты: Valgrind, AddressSanitizer −fsanitize=address-fsanitize=addressfsanitize=address, UBSan, gdb.

Правильный пример минимальнаякоррекцияминимальная коррекцияминимальнаякоррекция const char src = "This is a very long string";
size_t len = strlensrcsrcsrc + 1;
char s = malloclenlenlen;
if !s!s!s { perror("malloc"); exitEXITFAILUREEXIT_FAILUREEXITF AILURE; }
memcpys,src,lens, src, lens,src,len; / или strcpy после корректного выделения /
printf("%s\n", s);
freesss;
s = NULL;

Альтернатива удобноибезопасно,еслидоступноудобно и безопасно, если доступноудобноибезопасно,еслидоступно char s = strdup("This is a very long string");
if !s!s!s { / обработка */ }
printf("%s\n", s);
freesss;

Инструменты статической/динамической проверки

Valgrind — обнаружит чтение/запись за пределами, use-after-free, утечки.AddressSanitizer clang/gccclang/gccclang/gcc — детектирует heap/stack overflow, use-after-free и т. п.Static analyzers clang−tidy,cppcheckclang-tidy, cppcheckclangtidy,cppcheck.

Подходы в современных языках вкратцевкратцевкратце

C++: std::string управляет выделением и размером; RAII std::uniqueptr,std::vectorstd::unique_ptr, std::vectorstd::uniquep tr,std::vector предотвращают утечки и use-after-free, если соблюдать семантику владения.Rust: система владения и borrow checker предотвращает use-after-free и многие ошибки времени выполнения; проверка границ в safe-коде исключает переполнение.Go/Java/C#/Python: сборщик мусора устраняет классического use-after-free; встроенные типы строк/массивов проверяют границы нетпереполнениябуферакаквCнет переполнения буфера как в CнетпереполнениябуферакаквC, хотя возможны логические ошибки и удержание памяти дольше, чем нужно.Но: в некоторых языках всё ещё можно вызывать небезопасные операции например,unsafeвRust,unsafeC−интерфейсынапример, unsafe в Rust, unsafe C-интерфейсынапример,unsafeвRust,unsafeCинтерфейсы, что требует осторожности.

Краткие рекомендации чек‑листчек‑листчеклист

Выделяйте len = strlensrcsrcsrc + 1.Проверяйте malloc/realloc.Не используйте strcpy с непроверенными буферами; предпочитайте безопасные функции/шаблоны.Не используйте указатель после free; ставьте NULL.По возможности используйте более высокоуровневые механизмы управления памятью std::string,strdup,vectorstd::string, strdup, vectorstd::string,strdup,vector или современные языки.Инструментируйтесь: ASan, Valgrind, статический анализ.

Если нужно, могу показать дополнительные примеры исправления кода сrealloc,расширениембуфера,использованиемasprintf/strdup,иливерсиинаC++/Rustс realloc, расширением буфера, использованием asprintf/strdup, или версии на C++/Rustсrealloc,расширениембуфера,использованиемasprintf/strdup,иливерсиинаC++/Rust.

12 Окт в 15:31
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир