testing-debugging · intermediate · ~15 min
Understand and implement generational handles to detect dangling pointers and use-after-free bugs.
Dangling pointers and Use-After-Free (UAF) vulnerabilities happen when code accesses memory after it has been freed. Generational indexing (generational arena / slot maps) detects stale references by attaching a monotonic version counter to each slot.
Given the slot and handle structures:
typedef struct {
void *data;
uint32_t generation;
int active;
} Slot;
typedef struct {
uint32_t index;
uint32_t generation;
} SlotRef;
Implement:
SlotRef slot_insert(Slot *slots, size_t cap, void *data);
void *slot_lookup(const Slot *slots, size_t cap, SlotRef ref);
int slot_remove(Slot *slots, size_t cap, SlotRef ref);
slot_insert: find the first inactive slot (active == 0). Set data = data, active = 1, increment generation by 1. Return a SlotRef with index and the updated generation. If no slot available or slots == NULL, return { .index = 0, .generation = 0 }.slot_lookup: if slots == NULL, ref.index >= cap, slot is not active, or slots[ref.index].generation != ref.generation, return NULL (prevents UAF!). Otherwise return slots[ref.index].data.slot_remove: if slots == NULL, ref.index >= cap, slot is not active, or generation mismatch, return -1. Otherwise mark active = 0, set data = NULL, and return 0.Slot table[4] = {0};
SlotRef r = slot_insert(table, 4, "resource1");
slot_lookup(table, 4, r); // returns "resource1"
slot_remove(table, 4, r); // returns 0
slot_lookup(table, 4, r); // returns NULL (stale handle!)
slots: array of Slot structures; cap: table capacity; ref: handle containing index and generation.
Safe pointer retrieval or NULL if stale/dangling; return 0/-1 for removal.
Generational counters must prevent use-after-free even if slot is reused.
#include <stddef.h>
#include <stdint.h>
typedef struct {
void *data;
uint32_t generation;
int active;
} Slot;
typedef struct {
uint32_t index;
uint32_t generation;
} SlotRef;
SlotRef slot_insert(Slot *slots, size_t cap, void *data) {
(void)slots; (void)cap; (void)data;
SlotRef r = {0, 0};
return r;
}
void *slot_lookup(const Slot *slots, size_t cap, SlotRef ref) {
(void)slots; (void)cap; (void)ref;
return NULL;
}
int slot_remove(Slot *slots, size_t cap, SlotRef ref) {
(void)slots; (void)cap; (void)ref;
return -1;
}
Forgetting to check generation equality; not incrementing generation when slot is reused.
Reusing an existing slot increments generation, invalidating old references; out-of-bounds index returns NULL.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.