|
|
Subscribe / Log in / New account

Hard truth

Hard truth

Posted Sep 17, 2025 8:24 UTC (Wed) by danielthompson (subscriber, #97243)
In reply to: Hard truth by Wol
Parent article: Comparing Rust to Carbon

> Apparently the C++ guys don't want memory-safe functions to be only
> allowed to call other memory-safe functions. Which is absolutely
> fundamental to Rust.

Curiously Rust moved even further on this for the 2024 edition: it is no longer assumed that unsafe functions should have unsafe bodies. At this point it is only an on-by-default warning but even within an unsafe function then the tools now strongly encourage the use of the unsafe keyword before accessing the superpowers.

https://doc.rust-lang.org/nightly/rustc/lints/listing/all...


to post comments

Hard truth

Posted Sep 17, 2025 22:55 UTC (Wed) by NYKevin (subscriber, #129325) [Link]

This is because it never made much semantic sense to allow unsafe functions to do unsafe things in their bodies in the first place. The unsafe keyword has two entirely different meanings:

- As a specifier on the function signature, it is part of the API, and signals that the function has nontrivial safety preconditions which are not enforced by the compiler. By convention, these preconditions are listed in the function's doc comment under the "Safety" header.
- As a block of code, it represents an acknowledgement that one or more operations inside of that block have safety preconditions which are not enforced, and a promise by the developer to uphold those preconditions manually. By convention, the block is commented with a SAFETY comment explaining why the applicable preconditions hold at that point in execution.

Because the compiler does not know what precondition the programmer is promising to uphold with any given unsafe block, nor the exact preconditions any given unsafe function or other unsafe operation* might require, it has no way of checking one against the other. It is therefore not unheard of for programmers to deliberately make all unsafe blocks as small as possible. If only one operation is wrapped in unsafe, then you only have to worry about the preconditions of that one operation, and will not accidentally make unrelated promises about constructs you wrongly believed were safe. Fortunately, Rust treats unsafe blocks (and blocks in general) as expressions, so you can pinpoint the unsafe operation you want to allow and leave the rest of the expression in safe code, if you so desire.

By allowing unsafe functions to do unsafe things in their bodies without a separate unsafe block, older Rust editions inappropriately conflated these two meanings. More importantly, they made it much harder to minimize the amount of code that falls within an unsafe block.

* To be pedantically correct, the compiler knows full well that a raw pointer needs to point at a live allocation of the correct type, if you want to dereference it, and the compiler has similar knowledge of most of the other unsafe superpowers. But the compiler does not know about all the state surrounding that raw pointer, so (for example) it does not know that the pointer is always valid for reads when some flag is set, or any more complicated variation of that pattern. You can write a wrapper which enforces such an invariant in safe code, but the implementation of that wrapper ultimately still needs to use unsafe internally. There is no workaround for this, because the whole point of unsafe is to function as an escape hatch for things the compiler does not understand.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds