Já bych rád ocitoval určitou pasáž dokumentace o unsafe rustu.
"It’s important to understand that unsafe doesn’t turn off the borrow checker or disable any other of Rust’s safety checks: if you use a reference in unsafe code, it will still be checked. The unsafe keyword only gives you access to these five features that are then not checked by the compiler for memory safety. You’ll still get some degree of safety inside of an unsafe block."
A toto porovnejte s C kde nejsou vůbec žádné garance.
Navíc, když sekneš nějakou paměťovou chybu v rustu tak se nejprve budeš dívat na unsafe bloky.
> Navíc, když sekneš nějakou paměťovou chybu v rustu tak se nejprve budeš dívat na unsafe bloky.
Jenže ta chyba právě může být v safe bloku, v tom je ten problém.
Cituji Rustonomicon:
This program is now unsound, Safe Rust can cause Undefined Behavior, and yet we only modified safe code. This is the fundamental problem of safety: it's non-local. The soundness of our unsafe operations necessarily depends on the state established by otherwise "safe" operations.
A dále:
Because it relies on invariants of a struct field, this unsafe code does more than pollute a whole function: it pollutes a whole module. Generally, the only bullet-proof way to limit the scope of unsafe code is at the module boundary with privacy.
Tak předně, ten článek, stejně jako tvoje příspěvky, je hodně tendenční. Tohle tvrzení:
Safe Rust can cause Undefined Behavior, and yet we only modified safe code
prostě není pravdivé. V Safe Rustu se v tom příkladu nic undefined neděje. Undefined chování nastane až v unsafe bloku, kde se nekontroluje, že je index do pole platný.
Popravdě nechápu, co vlastně řešíš a očekáváš? Divíš se, že je možné napsat unsound program s unsafe blokem? To ale přece všichni víme. Divíš se, že změnou safe kódu se začně dít něco undefined v unsafe kódu? Ale jistě, je to unsafe kód.
Když to vztáhnu na C, tak tam to funguje takhle:
unsafe {
int main() {
úplně celý C program
}
}
Opravdu ti to přijde srovnatelné s Rustem? Mně ani náhodou.
Ve výsledku to je podobné, protože v obou případech musíte kontrolovat celý program. Point je, že v Rustu při problémech nestačí kontrolovat jen unsafe bloky.
Takže znovu, kde undefined chování nastane? V unsafe bloku. Takže vím, na co se zaměřit, na unsafe bloky, což je typicky naprosto minimální část kódu. V C oprotimu tomu nemám záruky nikde, musím se zaměřit na celý program. To je zásadní rozdíl.
Ale ten unsafe blok je správně. Takže jak vám pomůže, že se na něj zaměříte?
Unsafe blok není správně, nekontroluje se tam, že index není mimo meze pole. Znovu se ptám, co očekáváš, když v unsafe bloku zavoláš unsafe funkci, která nekontroluje meze pole a sám to taky nezkontroluješ?
Takže ano, zaměřím se na unsafe blok a najdu v něm chybu. V C bych místo unsafe bloku musel zkoumat celý program.
Jde to obema smery. Jde napsat kod, kde chyba je v unsafe, ale segfault nastane v safe:
struct Engine {
fuel: u64,
}
struct Ship {
engine: Box<Engine>,
}
fn main() {
let mut ship = Ship { engine: Box::new(Engine { fuel: 42 }) };
unsafe {
let engine_ptr_ptr =
std::mem::transmute::<&mut Box<Engine>, *mut u64>(&mut ship.engine);
// Make the ship's .engine field point to address 0x1337.
*engine_ptr_ptr = 0x1337;
}
println!("Now in safe code!");
// Segfault happens here, because it tries to dereference address 0x1337.
println!("Fuel: {}", ship.engine.fuel);
println!("Done!");
}
Ale i naopak, ze chyba nastane v safe a pristup za hranice pole v unsafe:
fn index(idx: usize, arr: &[u8]) -> Option<u8> {
// Tohle je blbe, ma byt <, a je to v safe.
if idx <= arr.len() {
unsafe {
Some(*arr.get_unchecked(idx))
}
} else {
None
}
}
Tak to si nerozumíme, já reagoval na
> Unsafe blok není správně, nekontroluje se tam, že index není mimo meze pole.
Jednalo se o hodnocení unsafe bloku z Rustonomiconu a jen jsem chtěl říci, že takový kód jako v Rustonomiconu je i ve standardní knihovně Rustu. Tzn., pokud si autor toho komentáře myslí, že je to špatně (nebo není správně), tak to platí i pro standardní knihovnu.
Můžete například oddělit paměťový prostor safe a unsafe části. Samozřejmě stejně na to budete potřebovat pár volání OS, takže úplně safe to nebude.
Tady je článek, kde jsou takové myšlenky popsané: Fearless FFI: Memory Safety, Safer Dependencies, and Supply-Chain Attack Mitigation
Prvotnou príčinou nie je unsafe kód, ale prítomnosť nedefinovaného správania. Ak máte v kóde niečo, čo spôsobuje nedefinované správanie, prekladač aj napriek tomu predpokladá, že píšete kód podľa špecifikácie a nerobíte niečo, o čom je jasne napísané, že to robiť nemáte. A na základe tohto predpokladu prekladač optimalizuje podľa toho ako potrebuje. Takže môže nejaké veci vynechať, nejaké veci poprehadzovať v poradí atď. A to potom spôsobuje nestabilitu, atď.