Comment by UncleMeat
6 months ago
The core benefit of the borrow checker is not "make sure to remember to clean up memory to avoid leaks." The core benefits are "make sure that you can't access memory after it has been destroyed" and "make sure that you can't mutate something that somebody else needs to be constant." This is fundamentally a statement about the relationship between many objects, which may have different lifetimes and which are allocated in totally different parts of the program.
Lexically scoped lifetimes don't address this at all.
Well, the title (which is poorly worded as has been pointed out) refers to C3 being able to implement good handling of lifetimes for temporary allocations by baking it into the stdlib. And so it doesn't need to reach for any additional language features. (There is for example a C superset that implements borrowing, but C3 doesn't take that route)
What the C3 solution DOES to provide a way to detect at runtime when already freed temporary allocation is used. That's of course not the level of compile time checking that Rust does. But then Rust has a lot more in the language in order to support this.
Conversely C3 does have contracts as a language feature, which Rust doesn't have, so C3 is able to do static checking with the contracts to reject contract violations at compile time, which runtime contracts like some Rust creates provides, can't do.
> What the C3 solution DOES to provide a way to detect at runtime when already freed temporary allocation is used.
The article makes no mention of this, so in the context of the article the title remains very wrong. I could also not find a page in the documentation claiming this is supported (though I have to admit I did not read all the pages), nor an explanation of how this works, especially in relation to the performace hit it would result in.
> C3 is able to do static checking with the contracts to reject contract violations at compile time
I tries searching how these contracts work in the C3 website [1] and these seems to be no guaranteed static checking of such contracts. Even worse, violating them when not using safe mode results in "unspecified behaviour", but really it's undefined behaviour (violating contracts is even their list of undefined behaviour! [2])
[1]: https://c3-lang.org/language-common/contracts/
[2]: https://c3-lang.org/language-rules/undefined-behaviour/#list...
> The article makes no mention of this, so in the context of the article the title remains very wrong
The temp allocator implementation isn't guaranteed to detect it, and the article doesn't go into implementation details and guarantees (which is good, because capabilities will be added on the road to 1.0).
> I tries searching how these contracts work in the C3 website [1] and these seems to be no guaranteed static checking of such contracts.
No, there is no guarantee at the language level because doing so would make a conforming implementation of the compiler harder than it needs to be. In addition, setting exact limits may hamper innovation of compilers that wish to add more analysis but will hesitate to reject code that can be statically know to violate contracts.
At higher optimizations, the compiler is allowed to assume that the contracts evaluate to true. This means that code like `assert(i == 1); if (i != 1) return false;` can be reduced to a no-op.
So the danger here is then if you rely on the function giving you a valid result even if the indata is not one that the function should work with.
And yes, it will be optional to have those "assumes" inserted.
Already today in current compiler, doing something trivial like writing `foo(0)` to a function that requires that the parameter > 1 is caught at compile time. And it's not doing any real analysis yet, but it will definitely happen.
7 replies →
> What the C3 solution DOES to provide a way to detect at runtime when already freed temporary allocation is used.
I looked at the allocator source code and there’s no use-after-free protection beyond zeroing on free, and that is in no way sufficient. Many UAF security exploits work by using a stale pointer to mutate a new allocation that re-uses memory that has been freed, and zeroing on free does nothing to stop these exploits.
It doesn't zero on free, that's not what the code does. But if you're looking for something to prevent exploits, then no, this is not it, nor does it try to be.
How would you want that implemented?
3 replies →
That was already available in languages like Modula-2 and Object Pascal, as the blog post acknowledges the idea is quite old, and was also the common approach to manage memory originally with Objective-C on NeXTSTEP, see NSZone.
Hence why all these wannabe be C replacements, but not like Rust, should bring more to the table.
Agreed. I personally am interested in Rust after doing some research for parallel semantics. The state of the art language is usually some pure functional programming language coupled with a garbage collector, which is not suitable for the type of embedded development I'm thinking of.
Doing alias analysis on mutable pointers seems to be inevitable in so many areas of programming and Rust is just one of the few programming languages brave enough to embark on this idea.