os_labs/lab4/README.md

92 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Лабораторная работа №4
## Задание 1
Было выяснено, что если не инициализировать глобальные (статические) переменные,
то порядок их расположения в памяти не определён. На trunk-версии GCC глобальные
переменные располагаются в памяти в порядке их объявления. На trunk-версии Clang
статические переменные располагаются в порядке их использования.
Обратный порядок расположения переменных на стеке соблюдается только при компилировании
с помощью Clang. (Проверено на GCC 9.3.0, GCC 6.5.0, Clang 10.0.0)
Если выделять 256 Кб и выше, то память выделяется в mmap-области.
Адрес указателя можно получить с помощью оператора "амперсанд": `&pointer`.
`&p` вернёт адрес, где лежит указатель, в то время как `p` вернёт сам указатель.
## Задание 2
`name` будет перезаписан после второго вызова `scanf()`, но если второй ввод строки
будет меньше, чем первый, то в памяти останется часть первого ввода (с учётом нуль-терминала).
При попытке записи в `name1` (`name1[0]=name1[3]`) программа даст сигнал SIGSEGV. Согласно
стандарту, запись в переменные типа `char* a = "abc"` вызывает неопределённое поведение.
Но GCC хранит переменные, проинициализированные подобным образом, в секции `.rodata`.
## Задание 3
Разыменовывание нулевого указателя даёт неопределённое поведение. Как правило, это аварийное
завершение программы. В качестве примера были использованы получение значения по адресу 0x0
и вызов функции по тому же адресу. Второй пример вызывает аварийное завершение программы не
на всех платформах -- на AVR-микроконтроллерах, например, это вызовет перезагрузку.
## Задание 4
GDB остановится на сигнале SIGSEGV, в момент разыменовывания. Для получения значения по адресу
0x0 вывод будет выглядеть так:
```text
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555129 in main () at /home/sh1ft/CLionProjects/os-labs/lab4/null.c:25
25 int a = *p;
```
Для вызова по нулевому адресу вывод будет следующим:
```text
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
```
Стоит обратить внимание, что для второго случая был выведен лишь адрес аварийного завершения
работы, так как для неизвестной функции по этому адресу компилятор не сгенерировал символы
отладки.
## Задание 5
Valgrind с ключами `--leak-check=yes` сообщит, что программа попыталась обратиться к адресу,
не находящемуся в mapped-области, укажет номер строки в файле, где это произошло. Также Valgrind
выведет, что утечек памяти в программе нет, и завершит работу с кодом SIGSEGV.
## Задание 6
Valgrind с ключами `--vgdb-error=0 --leak-check=yes` даст возможность подключить отладчик GDB.
После присоединения к процессу Valgrind (`target remote | /usr/lib/valgrind/../../bin/vgdb`)
программа будет приостановлена на точке входа `_start`. Ввод команды `continue` продолжит
дальнейшее исполнение программы. Также можно поставить брейкпоинт на определённую строчку кода
командой `break <srcfile>:<lineno>`, условный -- `break <srcfile>:<lineno> if <condition>`.
Программа без освобождения памяти успешно завершит работу, не вызвав остановки в отладчике,
но Valgrind заметит, что был утерян один блок памяти.
## Задание 7
Ошибка в коде видна невооружённым глазом -- выход за границы массива. Но программа успешно завершит
работу во всех случаях, за исключением граничных случаев, когда по адресу сразу после массива идёт
другая страница памяти. Но Valgrind следит за памятью приложения строже, чем операционная система --
некорректное обращение к памяти будет сразу замечено, о чём будет сообщено:
```text
==2088068== Invalid write of size 4
==2088068== at 0x109159: main (task7.c:7)
==2088068== Address 0x4a7c1d0 is 0 bytes after a block of size 400 alloc'd
==2088068== at 0x483977F: malloc (vg_replace_malloc.c:309)
==2088068== by 0x10914A: main (task7.c:6)
```
## Задание 8
Use-After-Free -- классическая ошибка при работе с динамической памятью. Они не всегда заметны,
особенно если программа успешно выполняется в большинстве случаев (как в этом, например). К
счастью, Valgrind определяет и такие ошибки. В IDE CLion встроена графическая обёртка для данного
инструмента, которая и была использована при выполнении этого задания.
![Valgrind GUI in CLion](valgrind_clion.png)