Хотим обезопасить стек от посторонних записей.
Переполнение буфера стека происходит, когда программа выполняет запись в адрес памяти в стеке вызовов программы за пределами предполагаемой структуры данных. Это почти всегда приводит к повреждению смежных данных в стеке, что может привести к сбоям программы, неправильной работе или проблемам безопасности.
Канарейки или канареечные слова - это известные значения, которые помещаются между буфером и управляющими данными в стеке для отслеживания переполнения буфера. При переполнении буфера первыми поврежденными данными обычно будут данные канарейки, поэтому проверка данных канарейки будет предупреждать о переполнении, которое затем может быть обработано, например, путем аннулирования поврежденных данных.
Есть динамический стек, в конце и в начале которого есть канарейки. Сам стек хешируется. И после каждого действием над стеком происходит проверка хеша и валидности канареек.
Есть структура в файле stack.h
typedef struct {
StackElement* array; # Стек
int64_t size; # Размер массива
StackElement CANARY = rand(); # Рандомное значение канарейки
int64_t capacity; # Вместимость стека
uint64_t hash; # Значение хеша
} IronStack;
Для которой есть методы:
- Вставка
void Push(IronStack& Stack, StackElement new_el) # вставляет элемент new_el в стек
. - Удаление
StackElement Pop(IronStack& Stack) # удаляет и возвращает верхний элемент
. - Просмотр элементов
StackElement Top(IronStack& Stack) # возвращает верхний элемент
. - Просмотр размера
int64_t Size(IronStack& Stack) # возвращает текующий размер стека
.
Так как стек динамический, есть метод IronStack Reallocate(IronStack& Stack, int64_t new_capacity)
.
На вход подаются стек и его желаемая вместимость. Метод вызывается самостоятельно, если в случае вставки элемента не хватает места. Вместимость в этом случае увеличивается в 2 раза.
Функция void Check(IronStack& Stack)
проверяет все канарейки.
Отдельно пишется фунция uint64_t hashing (IronStack& Stack)
, которая выполняет хеширование стека и возвращает хеш, соответствующий стеку.
Распределение хеш-функции на 10000 массивов размера 1000.
Из графика видим, что хеш-функция распределена равномерно.
Чтобы запустить проект используете команду
gcc ... -o main
\.main
Также проект подразумевает покрытие каждой функции тестами, которые лежат в test.h
Чтобы запустить проект с тестами используйте флаг:
-DTEST_BUILD