What's like the most unsafe thing i can do

without the unsafe block, what can possibly cause some kind of memory bug, or race condition, or the closest thing to ub.

my only very minor experience was having a for loop, loop through more elements than needed causing weird stuff, but that's obviously not something related to unsafe code

You can leak memory, use Mutexes to create a deadlock, or simply loop forever causing a function to never return.

If you consider a memory leak to be a memory bug, then this qualifies. This is not a "memory safety" problem, however, which is prevented by safe Rust.

A deadlock can be created by a race condition, so this qualifies. This is not a "data race", however, which is prevented by safe Rust.

A function that never returns probably doesn't qualify.

2 Likes

And you can of course, in perfectly safe code, still create logic errors, which make your program vulnerable to exploits. Which also is, you know, pretty bad.

4 Likes

Theoretically, nothing! That's the point of the language.

In practice, there are:

9 Likes

Rust does not prevent logic bugs in general (though some APIs are designed to make doing the correct thing easier than shooting yourself in the foot). Your application hanging or crashing is among the more benign things since they're easy to notice. An application that keeps running but produces incorrect behavior can be far more dangerous.

A non-exhaustive list of things that are memory-safe as far as the language spec is concerned:

  • the other 30% of security vulnerabilities
  • DoS
  • corrupting the filesystem
  • overwriting firmware
  • killing humans
  • bugs in business logic that ruin a company
  • overclocking the system until it becomes unstable
8 Likes

I once found I had written something that boils down to this:

fn bad(src_stream: &mut Stream, dst_stream: &mut Stream) -> Result<()> {
    let mut message = [0u8; 256];
    loop {
        let length = src_stream.read(&mut message)?;
        let sensitive = check_data(&message);
        if !sensitive {
            dst_stream.write(&message)?;
        }
    }
}

This can result in sensitive data being sent to the destination. When a long sensitive message is followed by a short non-sensitive message. The problem being that the write should have been:

dst_stream.write(&message[0..length])?;

This is not a memory safety bug or UB, it's a simple logic error. But when I discovered it, after the code had passed the tests in place, it felt like one of those buffer overrun kind of things one does in C.

5 Likes

I'm supprised no one has mentioned the possibility of stack overflow, for example, recursion level is too deep (or infinite), or create a value of very large type on the stack.

one of the most frustrating examples is that, rust does NOT guarentee (as I understand it) to elide the move from a temporary value on stack when creating a Box, and this can crash the program if the size of the type is very large. see e.g.

I should mention, this behavior is more commonly seen in debug builds, but they can appear in release builds too, when the use case is not as simple.

It's not unsafe to upload your bank password to pastebin, for example.

unsafe is about whether the code has defined behaviour where the logging makes sense, where you can use code inspection to think about what it's doing, etc. You can still do all kinds of horrible-for-a-user things without unsafe; it's just that it'll be what the code says to do.

6 Likes

I'm pretty sure from what the OP says in their question that they are well aware of the difference between the Rust definition of the unsafe keyword and the more general use of the word in security and safety critical software worlds etc.

This is showcased in one of my favorite joke crates: cve-rs

Note that unsafe is not perfect.

There is
Totally safe transmute

Anywhere it's not perfect is a bug, as was said above.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.