let x = String::from("foo");
let y = x;
println!("{}", x); // error: borrow of moved value: `x`
// C++: similar but differentauto x = std::string("foo");
auto y = std::move(x);
std::cout << x << std::endl; // ok, `x` is in valid but unspecified state
Ownership
#[derive(Debug)]structMyString(String);
fnfoo1(s: String) { println!("len: {}", s.len()); }
fnfoo2(s: String) -> MyString { println!("len: {}", s.len()); MyString(s) }
pubfnmain() {
let x = String::from("foo");
foo1(x);
let x = String::from("bar");
let x = foo2(x);
println!("{:?}", x);
}
Borrowing
Multiple immutable references, or
Single mutable reference
let x = String::from("foo");
let y = &x;
let z = &x;
println!("{}, {}, {}", x, y, z); // ok
letmut x = String::from("foo");
let y = &mut x;
let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time
y; z;
Borrowing
letmut x = 0;
let y = &x;
x = 42; // error: cannot assign to `x` because it is borrowed// *(&mut x) = 42; // basically the same thing
y;
letmut x = 0;
let y = &mut x;
*y = 42; // ok
x; // error: cannot use `x` because it was mutably borrowed// *(&x); // basically the same thing
y;
Smart Pointers
Box<T>: data on the heap
let x = Box::new(42);
letmut y = x;
*y += 1;
// there is no `y = nullptr` in Rust
// C++auto x = std::make_unique<int>(42);
auto y = std::move(x);
*y += 1;
y = nullptr;
auto z = *y; // runtime error: segmentation fault
Smart Pointers
Rc<T>: multiple ownership (reference count)
fnfoo(val: Rc<String>) { val; /* consumes val */ }
let x = Rc::new(String::from("foo"));
foo(x.clone()); // pass a clone of Rc, instead of moving `x` inprintln!("{}", x); // ok
intsomeos_file_write(int fd, void *buf, size_t count){
int ret, cnt, remain = count; // implicit conversion// ...while (remain > 0) {
fr->count /* ssize_t */ = cnt = MIN(remain, FS_BUF_SIZE);
memcpy(fr->buf, buf, cnt);
// write to file, ret is: 1) < 0 for failure; 2) >= 0 for bytes written
ret = ipc_call(fr);
buf = (char *)buf + ret; remain -= ret;
if (ret != cnt) break;
}
return count - remain;
}
Spatial Memory Safety
At least 4 bugs in the above C code!
int fd: fd can be negative or zero
void *buf: buf can be null or have unmatched size
remain = count: remain can be negative or very large due to unmatched type
ret = ipc_call(fr);: no error checking for ret
Spatial Memory Safety
What features of Rust can help?
Null safety
Type safety
Boundary check
Error handling
Spatial Memory Safety
Same thing implemented in Rust:
fnsomeos_file_write(fd: FileDescriptor, buf: &mut [u8]) -> SomeOsResult<usize> {
let count = buf.len();
letmut written = 0usize;
while written < count {
let buf_slice = &mut buf[written..min(written + FS_BUF_SIZE, count)];
let n = ipc_call(buf_slice)?;
written += n;
if n < buf_slice.len() {
break;
}
}
Ok(written)
}
Spatial Memory Safety
What if forgot min(written + FS_BUF_SIZE, count)?
let buf_slice = &mut buf[written..written + FS_BUF_SIZE];
If written + FS_BUF_SIZE is larger than buf.len(), it'll panic:
thread 'main' panicked at 'range end index 1024 out of range for slice of length 512'
Tock: An embedded OS for low-memory and low-power microcontrollers
RedLeaf: A new OS aimed at leveraging Rust language features for developing safe systems
Theseus: A new OS for experimenting with novel OS structure, better state management, and how to shift OS responsibilities like resource management into compiler
rCore: A teaching OS based on BlogOS, providing a subset of Linux syscalls