尊龙凯龙时官网进入网页

新闻动态

尊龙体育网大概与其他库和系统调用集成的缱绻-尊龙凯龙时官网进入网页

发布日期:2026-02-03 23:47    点击次数:202

尊龙体育网大概与其他库和系统调用集成的缱绻-尊龙凯龙时官网进入网页

尊龙体育网

Rust 因其坚忍的安全性能而备受宠爱,尤其是在内存安全和线程安全方面。但是,这是否意味着唯有使用 Rust,就一定能幸免编写出不安全的代码呢?事实并非如斯。在某些场景下,诞生者不得不使用 unsafe Rust 来完成任务,这也带来了潜在的安全隐患。那么,如安在这些不可幸免的情况下,最猛进度地裁减风险,确保代码的可靠性呢?

特斯拉工程师 Colin Breck 针对此问题撰文,转头了三种有用的施行措施,但愿能对诞生者有所裨益。

原文:https://blog.colinbreck.com/making-unsafe-rust-a-little-safer-tools-for-verifying-unsafe-code/

作家 | Colin Breck 责编 | 苏宓

出品 | CSDN(ID:CSDNnews)

Rust 之是以能成为一种流行的系统编程道话,其中一个原因是它具有出色的性能,同期不错在编译时排斥内存和并发颠倒,而这些颠倒在其他具有雷同性能特质的道话(如 C 和 C++)中很难幸免。不外,诞生者不错通过编写 unsafe Rust 代码来绕过这些编译时查验。尽管绝大浩荡神志员不应编写不安全的 Rust 代码,但一些库出于性能需求、以及径直操作内存或硬件,大概与其他库和系统调用集成的缱绻,使用了不安全的 Rust 代码。

接下来,本文将探讨考证不安全 Rust 代码的用具,包括从 C 或 C++ 编写的库中调用的不安全代码。现下我思要深切这一主题,主要缱绻亦然思为运营技能(OT)和重要基础设施编写安全且可靠的软件。

内存检测用具 Sanitizers

Sanitizers 是一种启动时用具,有益用来检测神志启动中的问题,比如内存损坏、内存线路或线程之间的数据竞争。它的责任旨趣是在编译代码时自动插入查验机制,匡助考证神志的举止是否日常。在使用 Sanitizers 时固然它会引入内存和性能支拨,但常常仅用于测试环境中。浩荡的是,与编译器不同,Sanitizer 只可检测在启动时本色被奉行的代码旅途中的颠倒——这不错通过测试或径直启动神志来结束。

当我第一次得知 Rust 复古用于查找颠倒的 Sanitizers 时,我感到很诧异。因为过往,我相比熟练如安在 C 和 C++ 中通过 Clang 和 LLVM 编译器使用 Sanitizers。由于 Rust 的编译器 rustc 亦然基于 LLVM 构建的,它雷同不错使用这些 Sanitizers。

内存越界打听/缓冲区溢出

看一下底下的神志:

fn bad_address(i: i32) -> i32 {\nlet xs: [i32; 4] = [0, 1, 2, 3];\nxs[i as usize]\n}\n\n\nfn main() {\nlet v = bad_address(4);\nprintln!(\"Value at offset: {}\", v);\n}

当我使用 RUST_BACKTRACE=1 cargo run --release 启动神志时,Rust 的限制查验检测到了颠倒,神志会 panic(崩溃):

thread 'main' panicked at src/main.rs:3:5:\nindex out of bounds: the len is 4 but the index is 4\nstack backtrace:\n0: _rust_begin_unwind\n1: core::panicking::panic_fmt\n2: core::panicking::panic_bounds_check\n3: sanitizers::main

神志被间隔,这种情况可能是诞生者极不肯看到以致是难以选择的,尤其当该软件对重要基础设施的启动至关浩荡时,可能会激励其他安全问题。但是,启动时查验可确保神志长久不会奉行导致未界说举止的不安全代码。

当今研讨一种情况——若是该函数在一个 unsafe 代码块中使用指针索引数组会发生什么:

fn bad_address(i: i32) -> i32 {\nlet xs: [i32; 4] = [0, 1, 2, 3];\nunsafe { *xs.as_ptr().offset(i as isize) }\n}\n\nfn main() {\nlet v = bad_address(4);\nprintln!(\"Value at offset: {}\", v);\n}

在不安全代码中,Rust 编译器不再提供内存和线程安全的保险。神志员需要我方确保不安全代码是适合划定的,而况不会导致未界说举止。当我启动这段代码时,即使神志读取了数组限制外的内存,也不会触发 panic。

Value at offset: 24576

Rust 的 AddressSanitizer 不错襄理查验代码中对堆栈和堆的越界打听。它的旨趣是,AddressSanitizer 通过在内存分派之间插入一些“红区”(red-zones),这些区域不可被打听,同期使用影子内存(shadow memory)跟踪内存是否被违纪读写。若是神志打听了不该碰的内存,AddressSanitizer 就会报错。需要隆重的是,这个用具只可在 Rust 的 nightly 版块中使用,不可用在踏实版上。但别惦记,nightly 和踏实版用具链不错同期安设,不会相互影响。要安设 nightly 用具链,你不错这么操作:

rustup install nightly

然后启动 AddressSanitizer 启动神志:

export RUSTFLAGS=-Zsanitizer=address\ncargo +nightly run

神志会因为越界打听而崩溃,并生成精通的颠倒敷陈:

=================================================================\n==96148==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x00016dce67b0 at pc 0x00010211bf70 bp 0x00016dce6770 sp 0x00016dce6768\nREAD of size 4 at 0x00016dce67b0 thread T0\n#0 0x00010211bf6c in array_out_of_bounds_unsafe::bad_address::h9a9dae85f9ad5feb array_out_of_bounds_unsafe.rs:3\n#1 0x00010211c170 in array_out_of_bounds_unsafe::main::hc84cbff8319e0a2b array_out_of_bounds_unsafe.rs:7\n#2 0x00010211bd40 in core::ops::function::FnOnce::call_once::hc75a52fb9134d583 function.rs:250\n#3 0x00010211bd8c in std::sys::backtrace::__rust_begin_short_backtrace::h9c09c1d17c8393c3 backtrace.rs:152\n#4 0x00010211b888 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h3a3a442dfff79e34 rt.rs:195\n#5 0x000102135230 in std::rt::lang_start_internal::hc996363c321dd410+0x440 (array_out_of_bounds_unsafe:arm64+0x10001d230)\n#6 0x00010211b6c0 in std::rt::lang_start::hae3ff67dcefd99eb rt.rs:194\n#7 0x00010211c2e0 in main+0x20 (array_out_of_bounds_unsafe:arm64+0x1000042e0)\n#8 0x00019d87e0dc ()\n#9 0xf4687ffffffffffc ()\n\n\nAddress 0x00016dce67b0 is located in stack of thread T0 at offset 48 in frame\n#0 0x00010211bdbc in array_out_of_bounds_unsafe::bad_address::h9a9dae85f9ad5feb array_out_of_bounds_unsafe.rs:1\n\n\nThis frame has 1 object(s):\n[32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable\nHINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork\n(longjmp and C++ exceptions *are* supported)\nSUMMARY: AddressSanitizer: stack-buffer-overflow array_out_of_bounds_unsafe.rs:3 in array_out_of_bounds_unsafe::bad_address::h9a9dae85f9ad5feb\nShadow bytes around the buggy address:\n0x00016dce6500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n=>0x00016dce6780: f1 f1 f1 f1 00 00[f3]f3 00 00 00 00 00 00 00 00\n0x00016dce6800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6880: 00 00 00 00 f1 f1 f1 f1 f8 f8 f2 f2 f8 f8 f8 f8\n0x00016dce6900: f8 f8 f2 f2 f2 f2 04 f3 00 00 00 00 00 00 00 00\n0x00016dce6980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n0x00016dce6a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\nShadow byte legend (one shadow byte represents 8 application bytes):\nAddressable: 00\nPartially addressable: 01 02 03 04 05 06 07\nHeap left redzone: fa\nFreed heap region: fd\nStack left redzone: f1\nStack mid redzone: f2\nStack right redzone: f3\nStack after return: f5\nStack use after scope: f8\nGlobal redzone: f9\nGlobal init order: f6\nPoisoned by user: f7\nContainer overflow: fc\nArray cookie: ac\nIntra object redzone: bb\nASan internal: fe\nLeft alloca redzone: ca\nRight alloca redzone: cb\n==96148==ABORTING

上述这一示例是在 debug 时势下启动的。若是在 release 时势下启动,由于编译器优化,可能无法识别到该颠倒。因此,在 release 构建中使用 Sanitizer 时,务必禁用编译器优化:

export RUSTFLAGS=\"-C opt-level=0 -Zsanitizer=address\"\ncargo +nightly run --release

值得一提的是,AddressSanitizer 不是每次皆能发现内存越界的问题。在前边的例子中,神志的融会取决于我打听数组时用的索引值:神志可能日常启动,也可能因为打听了未知地址而报 SEGV 颠倒,大概因为堆栈溢出径直崩溃。

数据竞争

为了竣工商量 Sanitizer(检测用具)尊龙体育网,我还思分享另一个示例,商量一下在不安全 Rust 代码中出现的颠倒不错通过 Sanitizer 检测到的措施。再来看一下以下代码,该代码从不同线程中的不安全代码打听分享的可变变量:

fn main() {\nstatic mut A: usize = 0;\n\n\nlet t = std::thread::spawn(