The idiomatic way to handle that is with some combination of `defer` and `errdefer`. Then, in code, there are no lines between alloc/free, and if a try would exit before the free then you would instead first free anyway.
> drop semantic is better in that regard
The drop trait has its warts too. Zig's version sets up a point in time where the given cleanup code _will_ run (ignoring power outages and the like), and Rust's sets up a point in time where the given cleanup code is _allowed_ to run. It solves UAF, but it makes performance harder to reason about and makes leaks easier to write (a common theme in my complaints about Rust -- it's mostly a nice language, but many of the design choices slightly encourage leaky code, so most projects of any size and complexity have leaks). Having drops be that easy to write also encourages programmers to think in terms of small units of data rather than collections and common lifetimes, typically resulting in increased execution times.