Rust的內(nèi)存安全依賴(lài)于強(qiáng)大的類(lèi)型系統(tǒng)和編譯時(shí)檢測(cè),不過(guò)它并不能適應(yīng)所有的場(chǎng)景。 首先,所有的編程語(yǔ)言都需要跟外部的“不安全”接口打交道,調(diào)用外部庫(kù)等,在“安全”的Rust下是無(wú)法實(shí)現(xiàn)的; 其次,“安全”的Rust無(wú)法高效表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu),特別是數(shù)據(jù)結(jié)構(gòu)內(nèi)部有各種指針互相引用的時(shí)候;再次, 事實(shí)上還存在著一些操作,這些操作是安全的,但不能通過(guò)編譯器的驗(yàn)證。
因此在安全的Rust背后,還需要unsafe
的支持。
unsafe
塊能允許程序員做的額外事情有:
*const T
和*mut T
let x = 5;
let raw = &x as *const i32;
let points_at = unsafe { *raw };
println!("raw points at {}", points_at);
static mut
static mut N: i32 = 5;
unsafe {
N += 1;
println!("N: {}", N);
}
unsafe fn foo() {
//實(shí)現(xiàn)
}
fn main() {
unsafe {
foo();
}
}
unsafe
unsafe fn
不安全函數(shù)標(biāo)示如果調(diào)用它可能會(huì)違反Rust的內(nèi)存安全語(yǔ)意:
unsafe fn danger_will_robinson() {
// 實(shí)現(xiàn)
}
unsafe block
不安全塊可以在其中調(diào)用不安全的代碼:
unsafe {
// 實(shí)現(xiàn)
}
unsafe trait
不安全trait及它們的實(shí)現(xiàn),所有實(shí)現(xiàn)它們的具體類(lèi)型有可能是不安全的:
unsafe trait Scary { }
unsafe impl Scary for i32 {}
對(duì)于Rust來(lái)說(shuō)禁止你做任何不安全的事是它的本職,不過(guò)有些是編寫(xiě)代碼時(shí)的bug
,它們并不屬于“內(nèi)存安全”的范疇:
使用unsafe
時(shí)需要注意一些特殊情形:
&mut T
和&T
遵循LLVM范圍的noalias
模型,除了如果&T
包含一個(gè)UnsafeCell<U>
的話(huà)。不安全代碼必須不能違反這些重疊(aliasing)保證UnsafeCell<U>
改變一個(gè)不可變值/引用std::ptr::offset
(offset功能)來(lái)索引超過(guò)對(duì)象邊界的值,除了允許的末位超出一個(gè)字節(jié)std::ptr::copy_nonoverlapping_memory
(memcpy32/memcpy64功能)bool
中一個(gè)不是false
(0)或true
(1)的值enum
中一個(gè)并不包含在類(lèi)型定義中判別式char
中一個(gè)代理字(surrogate)或超過(guò)char::MAX的值str
中非UTF-8字節(jié)序列