Rust使用动态检查方法来检查很多东西.一个这样的例子是数组的边界检查.
以此代码为例,
fn test_dynamic_checking() -> i32 {
let x = [1, 2, 3, 4];
x[1]
}
Run Code Online (Sandbox Code Playgroud)
由此产生的LLVM IR是:
; Function Attrs: uwtable
define internal i32 @_ZN10dynamic_ck21test_dynamic_checking17hcef32a1e8c339e2aE() unnamed_addr #0 {
entry-block:
%x = alloca [5 x i32]
%0 = bitcast [5 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* bitcast ([5 x i32]* @const7091 to i8*), i64 20, i32 4, i1 false)
%1 = getelementptr inbounds [5 x i32], [5 x i32]* %x, i32 0, i32 0
%2 = call i1 @llvm.expect.i1(i1 false, i1 false)
br i1 %2, label %cond, label %next
next: ; preds = %entry-block
%3 = getelementptr inbounds i32, i32* %1, i64 1
%4 = load i32, i32* %3
ret i32 %4
cond: ; preds = %entry-block
call void @_ZN4core9panicking18panic_bounds_check17hcc71f10000bd8e6fE({ %str_slice, i32 }* noalias readonly dereferenceable(24) @panic_bounds_check_loc7095, i64 1, i64 5)
unreachable
}
Run Code Online (Sandbox Code Playgroud)
插入分支指令以确定索引是否超出边界,这在clang编译的LLVM IR中不存在.
这是我的问题:
从概念上讲,Rust对每个阵列访问执行数组绑定检查.但是,编译器非常善于优化掉检查,因为它可以证明这样做是安全的.
LLVM中间输出具有误导性,因为在生成机器组件之前,LLVM的优化机制仍会对其进行优化.检查程序集输出的更好方法是使用调用生成最终程序集,例如rustc -O --emit asm --crate-type=lib.您的函数的汇编输出只是:
push rbp
mov rbp, rsp
mov eax, 2
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
不仅没有绑定检查,没有数组开始,编译器已经优化了整个函数return 2i32!要强制绑定检查,需要编写函数,以便Rust无法证明它可以被省略:
pub fn test_dynamic_checking(ind: usize) -> i32 () {
let x = [1, 2, 3, 4];
x[ind]
}
Run Code Online (Sandbox Code Playgroud)
这会导致更大的程序集,其中绑定检查实现为以下两个指令:
cmp rax, 3 ; compare index with 3
ja .LBB0_2 ; if greater, jump to panic code
Run Code Online (Sandbox Code Playgroud)
这是有效的.关闭绑定检查很少是一个好主意,因为它很容易导致程序崩溃.它可以完成,但只能在unsafe块或函数的范围内明确地完成:
pub unsafe fn test_dynamic_checking(ind: usize) -> i32 () {
let x = [1, 2, 3, 4];
*x.get_unchecked(ind)
}
Run Code Online (Sandbox Code Playgroud)
所述生成组件示出了错误检查,以完全省略:
push rbp
mov rbp, rsp
lea rax, [rip + const3141]
mov eax, dword ptr [rax + 4*rdi]
pop rbp
ret
const3141:
.long 1
.long 2
.long 3
.long 4
Run Code Online (Sandbox Code Playgroud)