3 ms·
Short answer: not exactly, no. Long answer: Zig does a lot of stuff to make the easy way of dealing with memory the correct way. The typical pattern is to use
by AnIdiotOnTheNet 4y ago
Short answer: not exactly, no.
Long answer: Zig does a lot of stuff to make the easy way of dealing with memory the correct way. The typical pattern is to use defer/errdefer statements to clean up on end of scope or in case of error. One of the included allocators checks for leaks and use after free, and it is trivial to change which allocator is used based on build mode. It is also very strict about pointers and has a whole lot of different kinds to represent different use cases and include appropriate safety checks (in safe and debug modes) when dealing with them.
- throwawaymaths 4y agoLonger answer: I think it's inevitable that someone will write a static checker for lifetime analysis.
- kaba0 4y agoThat’s pretty much impossible in the general case, thanks to Rice’s theorem. Rust can only do so because it limits the possible lifetime “shapes”. Otherwise why don’t build it for C instead?
- throwawaymaths 4y agoRust doesn't do it either. It has 'unsafe'. So just as with rust, you would annonate certain things in zig as 'trusted', and anything else will be checked. For example, for pointers, assume allocator interface create, alloc, destroy, and free functions work as advertised, and trust them. Anything that uses the pointers is checked. For file descriptors, assume open and close are trusted, everything in between is checked. You can't really build it so easily for c because c language is not generally compiled to an IR, and the syntax is rather ill-defined. It's not context-free and it has lexical macros. Anyways statically checked annotated c exists, SEL4 is a good example, but iirc it actually checks arm machine code, and yes it is memory safe C.
- kaba0 4y agoWhat do you think C compilers work on if not IR? Also, it not being context-free is not a problem after parsing, that’s a different part of the process. This is about what we can claim about runtime properties. What exactly do you mean by a checked pointer? A pointer has temporal and spatial boundaries — will you add a huge amount of metadata to each pointer to runtime validate whether it’s correctly used? That’s pretty much what valgrind and sanitizers do, but that has quite an overhead. In general you can’t check it for any kind of pointer usage. Rust as I mentioned can get away with it by heavily restricting how pointers can be used. Unchecked is an escape hatch, you can’t just put the “checked” boundary at any place you wish, it has to be placed in a way that makes analysis of its assumed properties sound. In case of Rust this is true, but you would have to restrict Zig’s semantics to something like Rust’s to make your idea workable.
- throwawaymaths 4y ago> In case of Rust this is true, but you would have to restrict Zig’s semantics to something like Rust’s to make your idea workable. That's exactly the point. You would be restricting zig's semantics within code that you've fenced. You claim it's not possible. Trivially it should be possible, because this is simply the equivalent of abstracting rusts compiler logic (and in the worst case scenario even it's type system, via annotations) to a sidecar step that is run at a different phase of building your code. Or, more generically, formalizing logic that a code reviewer is doing in their head to understand data lifecycles. Really, to support your impossibility claim: It's on you to give an example of zig code that wouldn't be analyzable.
- kaba0 4y agoI think we misunderstand each other on what is “inside-outside”. Sure, you can have a tiny “safe” block in zig, but that won’t be able to use any outside pointer safely, and I don’t see much point in that — is that what you mean? Because unless you say that, then no. Also surely you can write some zig to rust compiler (which mind you, will not compile most of your programs as the equivalent rust is not semantically correct), but there is not much point. Re code: let ptr = allocate(); if (undecideableProperty()) { destroy ptr; } print(*ptr); Insert any number of undecidable property there, one elegant example would be the Goldbach conjecture.