In what ways does Rust enforce memory safety other than ownership & borrowing?

For example, I know that Rust performs bounds checking on arrays.

Are there any other ways Rust enforces memory safety?

It’s a simple concept that is rigorously implemented both in concrete and generic applications; non-trivial.

There are times when you need to write using “unsafe” code (e.g., using SIMD directly). The enforcement of safety rules are solid. That would include making sure changes in the memory types or configuration are consistent with what you’re trying to do. “What you’re trying to do” is conveyed to Rust by the type system and thus the type checker also makes your code that much safer.

Rust uses fat pointers that are explicit regarding where the end of a memory exists (stride + length) e.g., the end of a String is not marked by null (a chosen convention).

Speaking of null... traits like Option and Result to avoid partial functions...

So the list goes on depending on how you think about it.

1 Like

It's not going to let you use uninitialised memory.

Anything that acts like a pointer is always pointing to valid data of the correct type.

2 Likes

I mean, there are a lot of things it does, but arguably most of them fall into the category of ownership/borrowchecker.

I suppose one thing is that RefCell will panic if you use it in a way that could violate memory safety.

2 Likes

There's also the Send/Sync traits that ensure multi-threaded code is free of memory errors.

6 Likes
  • enum is a tagged union, and doesn't allow access to an invalid variant (unlike memory-unsafe union).

  • mutable globals are forbidden in safe Rust, unless they use concurrency primitives like Mutex.

  • Types and functions shared between crates are precisely namespaced and versioned, which ensures they have compatible ABI (as opposed to C headers and header include paths being technically separate from C library include paths, so these two could get out of sync).

2 Likes