"Use after free" is a symptom of other problems. You can "solve" it by making it very different to do in the first place with something ownership semantics, but there are usually better ways of dealing with it in the first place.
Because use-after-free is a responsibility problem, handles are a way to make sure that a subsystem has responsibility over that memory directly rather than have it spread out across the program.
This is why Odin nor Zig "solve" this problem: solving it at the language level is not necessarily the best option.
That’s essentially what Rust does: it makes using handles to get temporary access to memory that are owned in a single place very attractive because otherwise the borrow checker will yell at you.
One really good approach is to not use pointers in the first place and use handles. I highly recommend this post for more information: https://floooh.github.io/2018/06/17/handles-vs-pointers.html
Because use-after-free is a responsibility problem, handles are a way to make sure that a subsystem has responsibility over that memory directly rather than have it spread out across the program.
This is why Odin nor Zig "solve" this problem: solving it at the language level is not necessarily the best option.