Zig’s New Pointer Fix Is a Band-Aid on a Bullet Wound

You’ve felt that cold sweat. The production server spikes. The logs spit out a meaningless segfault. Somewhere in your code, a pointer is dangling—pointing to a memory address that has shifted, mutated, or vanished entirely. It’s the quiet dread of systems programming.

Recently, the Zig language announced a fix for this exact scenario in its ArrayLists. If an element moves during a reallocation and you try to use an old pointer to it, Zig will now trigger a panic, giving you a neat stack trace instead of silent memory corruption.

It sounds like a massive win for developer experience. But it’s not. It’s a lie.

A panic instead of a segfault is still a crash. The software still dies. You’ve just upgraded your autopsy report.

Here is the fundamental paradox of dynamic arrays: an ArrayList exists precisely because it needs to grow. To grow, it reallocates. To reallocate, it moves memory. Moving memory invalidates every single pointer pointing to that memory. You want O(1) amortized pushes with contiguous memory, and you also want your pointers to stay valid. Those two goals are fundamentally at war with each other.

Zig’s “fix” is just a runtime check layered over a design-level footgun. And worse, it’s a conditional fix. This panic only triggers in Debug and ReleaseSafe modes. When you compile for ReleaseFast—stripping out the checks to get raw, unhinged performance—the safety net evaporates. The very environment where you need safety the most is the one where it is deliberately disabled.

If you need a stable pointer to an item in a dynamic array, you have already lost. The data structure you chose is mathematically at odds with your requirements.

Think about it. Why are you holding a pointer to an element in a list that is actively resizing? If you want to reference an item, store an index. If the list is going to shuffle elements, use a different structure, like a linked list or a generational arena. Don’t try to weaponize a pointer into a structure that was designed to relocate.

The industry keeps treating memory safety as a runtime problem. We add garbage collectors. We add borrow checkers. We add debug panics. But the real issue isn’t that we need safer pointers—it’s that we keep choosing the wrong abstractions.

Memory safety isn’t about surviving bad code. It’s about making the architecture so obvious that the bad code never gets written in the first place.

Stop asking your language to save you from your data structures. If your pointers are dangling, don’t ask for a better safety net. Ask yourself why you’re walking the tightrope in the first place.

FAQ

Q: Isn't a stack trace better than a silent memory corruption?

A: Yes, for debugging. But a better autopsy doesn't save the patient. If your software crashes in production, the business impact is the same whether it's a segfault or a panic.

Q: So I should never use pointers with ArrayLists?

A: Exactly. If you need to reference an item in a dynamic array, store its index. If you need the memory address itself to remain stable, you need a different data structure, like an arena allocator.

Q: Is Zig wrong for adding this feature?

A: Zig isn't wrong, but they're treating the symptom, not the disease. The real issue is that low-level languages keep layering runtime checks over design-level footguns instead of forcing developers to use the right abstraction.

📎 Source: View Source