mirror of https://github.com/t1meshift/os_labs.git
Add 4th lab
parent
1de33e9192
commit
38b6a593e6
|
@ -14,4 +14,5 @@ function(define_lab lab_name)
|
|||
endfunction()
|
||||
|
||||
define_lab(lab2)
|
||||
define_lab(lab3)
|
||||
define_lab(lab3)
|
||||
define_lab(lab4)
|
|
@ -0,0 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
# Lab name
|
||||
set(LAB_NAME "lab4")
|
||||
|
||||
# Lab tasks
|
||||
list(APPEND SOURCE_FILES
|
||||
aspace.c
|
||||
task2.c
|
||||
null.c
|
||||
task6.c
|
||||
task7.c
|
||||
task8.c
|
||||
)
|
||||
list(APPEND NON_COMPILABLE_SRC
|
||||
# .execme
|
||||
)
|
||||
|
||||
set_source_files_properties(aspace.c PROPERTIES COMPILE_FLAGS -O0)
|
||||
#set_source_files_properties(null.c PROPERTIES COMPILE_FLAGS -DHANDLE_SIGSEGV)
|
||||
set_source_files_properties(null.c PROPERTIES COMPILE_FLAGS -g)
|
||||
set_source_files_properties(task6.c PROPERTIES COMPILE_FLAGS -g)
|
||||
set_source_files_properties(task7.c PROPERTIES COMPILE_FLAGS -g)
|
||||
set_source_files_properties(task8.c PROPERTIES COMPILE_FLAGS -g)
|
||||
|
||||
### Here goes the template
|
||||
|
||||
project("${LAB_NAME}" C)
|
||||
|
||||
add_custom_target("${LAB_NAME}")
|
||||
|
||||
foreach (file IN LISTS SOURCE_FILES)
|
||||
add_executable("${LAB_NAME}_${file}_run" "${file}")
|
||||
add_dependencies("${LAB_NAME}" "${LAB_NAME}_${file}_run")
|
||||
endforeach ()
|
||||
|
||||
foreach (file IN LISTS NON_COMPILABLE_SRC)
|
||||
add_custom_command(
|
||||
TARGET "${LAB_NAME}" POST_BUILD
|
||||
DEPENDS "${file}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${file}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${file}"
|
||||
)
|
||||
endforeach ()
|
|
@ -0,0 +1,92 @@
|
|||
# Лабораторная работа №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)
|
|
@ -0,0 +1,50 @@
|
|||
/* Example code for Think OS.
|
||||
|
||||
Copyright 2015 Allen Downey
|
||||
License: Creative Commons Attribution-ShareAlike 3.0
|
||||
|
||||
*/
|
||||
#define PRINT_DISTANCE(a, b) printf("Distance between " #a " and " #b ": %ld\n", (void *) (a) - (void *) (b))
|
||||
|
||||
#include <malloc.h>
|
||||
#include <mcheck.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int global;
|
||||
int another_global;
|
||||
|
||||
int main() {
|
||||
char malloc_trace_path[4096];
|
||||
getcwd(malloc_trace_path, 4096);
|
||||
strcat(malloc_trace_path, "/malloc_trace.txt");
|
||||
setenv("MALLOC_TRACE", malloc_trace_path, 0);
|
||||
mtrace();
|
||||
|
||||
int local = 5;
|
||||
int another_local = 7;
|
||||
void *p = malloc(128);
|
||||
void *another_p = malloc((1 << 18));
|
||||
|
||||
printf("Address of main is %p\n", main);
|
||||
printf("Address of global is %p\n", &global);
|
||||
printf("Address of local is %p\n", &local);
|
||||
printf("Address of another_local is %p\n", &another_local);
|
||||
printf("Address of p is %p\n", p);
|
||||
printf("Address of another_p is %p\n\n", another_p);
|
||||
|
||||
PRINT_DISTANCE(&global, &main);
|
||||
PRINT_DISTANCE(&global, &another_global);
|
||||
PRINT_DISTANCE(&local, &another_local);
|
||||
PRINT_DISTANCE(p, another_p);
|
||||
|
||||
malloc_stats();
|
||||
|
||||
FILE *minfo = fopen("malloc_info.xml", "w");
|
||||
malloc_info(0, minfo);
|
||||
fclose(minfo);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HANDLE_SIGSEGV
|
||||
void on_sigsegv() {
|
||||
printf("SIGSEGV\nNull pointer dereference gives UB.\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#ifdef HANDLE_SIGSEGV
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
action.sa_sigaction = on_sigsegv;
|
||||
sigaction(SIGSEGV, &action, NULL);
|
||||
#endif
|
||||
|
||||
// Dereference NULL
|
||||
int *p = NULL;
|
||||
//(*p)(); // Calling a function from 0x0, yay!
|
||||
int a = *p;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
void on_sigsegv() {
|
||||
printf("SIGSEGV\nWrite access to `char* a = \"abc\"` gives UB.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
action.sa_sigaction = on_sigsegv;
|
||||
sigaction(SIGSEGV, &action, NULL);
|
||||
|
||||
/* Assume name shorter than 20 chars. */
|
||||
char name[20];
|
||||
puts("Enter name: ");
|
||||
scanf("%19s", name);
|
||||
printf("Hello, %s.\n\n\tNice to see you.\n", name);
|
||||
|
||||
puts("Enter name: ");
|
||||
scanf("%19s", name);
|
||||
printf("Hello, %s.\n\n\tNice to see you.\n", name);
|
||||
|
||||
char *name1 = "Anna";
|
||||
char a_letter = name1[0];
|
||||
name1[0] = name1[3];
|
||||
name1[3] = a_letter;
|
||||
puts(name1);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main() {
|
||||
char *a = malloc(1024);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main() {
|
||||
int *data = malloc(100 * sizeof(int));
|
||||
data[100] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main() {
|
||||
int *data = malloc(100 * sizeof(int));
|
||||
free(data);
|
||||
|
||||
printf("%d\n", data[96]);
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 364 KiB |
Loading…
Reference in New Issue