对于大多数可能溢出的操作符,Rust 提供了一个检查版本。例如,要测试加法是否溢出,可以使用checked_add:
match 255u8.checked_add(1) {
Some(_) => println!("no overflow"),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
这打印"overflow!". 还有一个checked_shl, 但根据文档,它只检查移位是否大于或等于self. 这意味着虽然这个:
match 255u8.checked_shl(8) {
Some(val) => println!("{}", val),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
被捕获并打印"overflow!",这是:
match 255u8.checked_shl(7) {
Some(val) => println!("{}", val),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
只是打印128,显然没有捕捉到溢出。向左移动时检查任何类型溢出的正确方法是什么?
我遇到了意外的早期堆栈溢出并创建了以下程序来测试该问题:
#![feature(asm)]
#[inline(never)]
fn get_rsp() -> usize {
let rsp: usize;
unsafe {
asm! {
"mov {}, rsp",
out(reg) rsp
}
}
rsp
}
fn useless_function(x: usize) {
if x > 0 {
println!("{:x}", get_rsp());
useless_function(x - 1);
}
}
fn main() {
useless_function(10);
}
Run Code Online (Sandbox Code Playgroud)
这是get_rsp反汇编的(根据cargo-asm):
tests::get_rsp:
push rax
#APP
mov rax, rsp
#NO_APP
pop rcx
ret
Run Code Online (Sandbox Code Playgroud)
我不确定什么#APP和#NO_APP做什么或为什么rax被压入然后弹出rcx,但似乎该函数确实返回了堆栈指针。
我很惊讶地发现在调试模式下,两个连续打印之间的差异rsp是 192(!),甚至在发布模式下也是 128。据我所知,每次调用需要存储的useless_function只是一个usize和一个返回地址,所以我希望每个堆栈帧大约 16 …
我试图通过使用像 C 的灵活数组成员这样的东西来避免多个堆分配。为此,我需要分配一个未定义大小的结构,但我没有找到任何通过智能指针来实现的方法。我对 尤其感兴趣Rc,但这也是 的情况Box,所以这就是我将在示例中使用的内容。
这是我迄今为止最接近的:
use std::alloc::{self, Layout};
struct Inner {/* Sized fields */}
#[repr(C)] // Ensure the array is always last
// Both `inner` and `arr` need to be allocated, but preferably not separately
struct Unsized {
inner: Inner,
arr: [usize],
}
pub struct Exposed(Box<Unsized>);
impl Exposed {
pub fn new(capacity: usize) -> Self {
// Create a layout of an `Inner` followed by the array
let (layout, arr_base) = Layout::array::<usize>(capacity)
.and_then(|arr_layout| Layout::new::<Inner>().extend(arr_layout))
.unwrap(); …Run Code Online (Sandbox Code Playgroud)