> But use after free absolutely results in the same kinds of errors (accessing unused memory, or memory used by someone else).
That two bugs result in the same or similar outcome doesn't mean they're as common or as equally exploitable, which is why, in practice, it is distinctly a more dangerous weakness in the lists maintained by MITRE.
> I also don't understand how one can sidestep the issue of ownership of memory
It's not about side-stepping. There are many kinds of bugs in software, and while we'd like to avoid all of them, some problems are, in practice, more problematic. After all, Rust similarly "sidesteps" - as in doesn't prevent - all non-memory-safety-related weaknesses, some of which are more dangerous than dynamic memory safety. If Zig isn't good enough because it doesn't prevent temporal memory safety violations, then by the exact same logic, Rust isn't good enough because it doesn't prevent, say, injection vulnerabilities, that are more dangerous than temporal memory safety vulnerabilities.
> I'm not saying this just because, I've encountered this exact issue before
Sure, it's a real and serious issue. But injection is a more serious issue, which Rust doesn't prevent, and spatial memory violations are also a more serious issue, which Zig prevents just as Rust does.
> That's why it's important to make it either obvious who owns what, or have some automatic system like GC or unique_ptr or the borrow checker.
It is, but it's even more important to prevent code injection attacks, yet Rust doesn't do that. It all comes down to how much it's worth it to pay to prevent certain bugs.
Rust was built because its designers believed that memory safety wasn't worth paying the higher memory footprint or the lower predictability of more popular memory-safe languages, or else there would have been no need for Rust in the first place. Similarly, it's just as reasonable to believe that the price you pay for temporal memory safety in Rust is not worth it.
> You mention Zig has a temporal memory management solution of a different kind - may I ask you what it is, because I haven't really seen it.
It's not a safe solution by any means (as the language doesn't enforce temporal memory safety, just as C++ doesn't), but memory allocation and deallocation in Zig is not the same as in C or C++. In particular, Zig functions that allocate are explicitly marked by having an Allocator parameter (https://zig.guide/standard-library/allocators/). Unlike in C, in Zig you know which functions allocate and using which allocator. That's how Zig is such a great fit for arenas.
Because Zig is built around custom allocators, you can also choose allocators that offer use-after-free, double-free, and memory-leak protection, and do so selectively (unlike in C): https://sinclairtarget.com/blog/2025/09/getting-my-allocator...