Yes, I think so. In practice I usually isolate a single function call in an unsafe block, which with current notation means I have to put the arguments in separate variables first. The unsafe f(...) (or your unsafe.f(...)) notation would be a more natural way to isolate the unsafe code to that single call.
if safe needs to be guarateened in unsafe block, why not introduce another keyword?
I means, something like safe or !unsafe, which could only occurs in a unsafe block
unsafe let a=foo.safe().bar.safe().baz(); //SAFETY : baz called after `init`, thus it is safe.
By introducing safe keyword for safe functions to functions would help compling the program.
for safe functions foo, foo.safe == foo always holds, which is ensured by compiler
for unsafe functions, unsafe_foo.safe does not exist.
In this case programmer could easily check whether a call is safe.
While this does solve the issue of knowing which part of code is safe and which one is not, it feels like a pessimization of the most common kind of code (the safe one). Ideally we should be pessimizing the one that should be less common, i.e. the unsafe one.
I still think that focusing too much on which functions are safe or unsafe is the wrong direction for making this better. It's whether the preconditions are met that's really important, and turning Foo::new_unchecked(x) into unsafe.Foo::new_unchecked(x) or whatever isn't really helping to focus the effort on the important part.
The particularly-bad problems I see in unsafe code are not that people don't know which things are unsafe, but they end up focusing on proving one of the preconditions, but forget the other one.
Code like this is really common, for example:
let next_four: &[u8] = &slice[..4];
// SAFETY: The slicing on the previous line ensures that we have
// sizeof(u32) == 4 bytes to read, and `u8` can't have padding or
// be uninitialized, so the `u32` will always be valid.
unsafe {
ptr::read(next_four.as_ptr() as *const u32)
}
That's clearly someone really trying to do it right, and knowing which methods are unsafe and being good about writing down their reasoning. But it's still unsound, because they remembered two of the things but forgot about the alignment requirement.
So if we have something (sketch) that instead helps get the preconditions right, then we can have larger unsafe blocks again without issue.
Even better, if the preconditions can be accurately and completely declared, we shouldn't even need the unsafe.
#[safety_requires(aligned(ptr), readable(ptr))]
unsafe fn read<T>(ptr: *const T);
...
#[hold_my_beer(aligned(p), readable(p), aligned(q), readable(q))]
read(p) + read(q)
(which looks a lot like a newtype wrapper AlignedReadable that's unsafe to construct but with a safe .read() method)
Yeah, the big difference is in compositionality.
At some point it stops being fun to make the TwoPointersToArraysOfTheSameLength::new_unchecked(p, q, n) types, and delegating to a proof tool of some sort would be better.
You're solving a separate problem from what this thread is about.
Why not both?
let x =
#[hold_my_beer(aligned(p))]
unsafe read(p);
let y =
#[hold_my_beer(aligned(_))]
unsafe read(calc_pointer()); // calc_pointer has to be safe
This might sound like a silly reason, but I would prefer keeping the braces because it's easier to grep.
$ rg 'unsafe\W+{'
will find only unsafe blocks, not every thing with "unsafe" in its name, as opposed to rg unsafe. I hate debugging regular expressions, and unsafe\W+{ is complex enough for me.
'\bunsafe\b' will find unsafe keywords that are not part of a longer identifier.
That will also find unsafe functions, traits and unsafe impl of traits, not just unsafe blocks.
And it will find the word "unsafe" in strings and comments too.
Comments as well, with a unique artistic touch:
riscv-rust/wasm/web/xtermjs/xterm.js.map
1:{"version":3,"sources":["webpack:/
<hundreds of lines>
alue: T): void {\n // This is unsafe: See note above.\n let node = this._map[key]
In which cases do you need to grep for unsafe usage? Couldn't a tool similar to cargo-geiger which would output the detail of unsafe usage (instead of a summary) be more appropriate than rg ?
It is harder to reach for. And people are lazy.
This just shows that original grep 'unsafe\W+{' is even worse in some ways. If your goal is to review unsafe code, you should be also looking at unsafe impls of traits, and perhaps also at unsafe functions (since they implicitly create an unsafe block -- although this has a lint that can be enabled).
The original grep will also potentially match some identifiers ending with unsafe as well as some strings and comments, not just unsafe blocks.
Overall, I don't think this particular regular expression is a great argument against the unary unsafe.
Unary unsafe may make it easier to both write and review unsafe code because it would reduce the scope of unsafe.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.