#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

// Прагмы нужны для того, чтобы оптимизатор не выкинул половину нашего кода.
#pragma GCC push_options
#pragma GCC optimize "-O0"
static int is_admin = 0;
#pragma GCC pop_options

static void vulnerable(size_t index, size_t length)
{
    // Пишем безопасный код: запрещаем атакующему обращаться к данным за
    // пределами массива.
    if (index >= length) {
        printf("oops, the index is out of bounds\n");
        return;
    }
    
    // Выделяем память, обращаемся к ней. В общем-то ничего плохого не
    // делаем.
    uint8_t *ptr = malloc(length);
    printf("got some memory from malloc(): %p\n", (void *) ptr);
    ptr[index] = 1;
    free(ptr);
}

static void destroy_the_world(void)
{
   if (!is_admin) {
        printf("access denied\n");
        return;
   }

   printf("nuclear apocalypse in 3... 2... 1...\n");
}

int main(void)
{
    // Представим, что размер и индекс контролируются атакующим.
    size_t index_from_user = (size_t) &is_admin;
    size_t length_from_user = SIZE_MAX;

    printf("BEFORE: is_admin = %u\n", is_admin);
    vulnerable(index_from_user, length_from_user);
    printf("AFTER:  is_admin = %u\n", is_admin);
    
    destroy_the_world();
}