The idea: realloc can move everything
When a dynamic array grows, realloc may copy it to a new address and free the old block. Every pointer you handed out into the old block is now dangling: it points to freed memory.
Reading through it is a use-after-free. It often still "works" because freed memory is not erased right away. That is what makes it dangerous.
The situation
store_open returns a Session * that callers keep and use later, even after opening more sessions. The array of sessions grows with realloc.
Your mission
Run the sanitizer and read its report: where the block was allocated, where it was freed, and which function touched it afterwards. Then redesign the ownership so a session's address never changes, and tell the junior exactly how.
What to watch for
- Making the initial capacity huge only postpones the move. What happens after that?
- Changing a struct means changing the header too, and the function that frees everything.