为什么使用不安全代码的 rustdoc 测试会失败,但集成测试中的相同代码会通过?
Why does a rustdoc test with unsafe code fail but the same code in an integration test passes?
我正在尝试编写名为 insert
的方法的 rustdoc 测试。
在测试的最后一行调用了测试函数,当我把它注释掉时,测试通过了。
错误信息:
$ cargo test
Compiling reproduce v0.1.0
(file:///home/user/reproduce)
Finished dev [unoptimized + debuginfo] target(s) in 2.03s
Running target/debug/deps/reproduce-17ad4bb50aa9c47e
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests reproduce
running 1 test
test src/lib.rs - MyStruct::method (line 19) ... FAILED
failures:
failures:
src/lib.rs - MyStruct::method (line 19)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
error: test failed, to rerun pass '--doc'
代码:
impl MyStruct {
pub fn new(lsb: u8, step: usize) -> MyStruct {
let mask: u8 = match lsb {
1 => 0b0000_0001,
2 => 0b0000_0011,
_ => 0b0000_1111
};
MyStruct { lsb, mask, step }
}
/// # Examples
/// ```
/// extern crate reproduce;
/// extern crate rgb;
///
/// use std::slice;
/// use rgb::RGB;
///
/// let msg = "This is a secret message".as_bytes();
/// let img = vec![RGB {r: 0, g: 0, b: 0}; 800*500];
///
/// // Create a reference to the bytes of img
/// let p: *const Vec<RGB<u8>> = &img;
/// let p: *const u8 = p as *const u8;
/// let p: &[u8] = unsafe {
/// slice::from_raw_parts(p, 3*800*500)
/// };
///
/// let settings = reproduce::MyStruct::new(2, 12);
/// let new_data = settings.method(p, &msg);
/// ```
pub fn method(&self, img: &[u8], msg: &[u8]) -> Vec<u8> {
let mut ret = img.to_vec();
let mut n = 0;
for ch in msg.iter() {
for i in 1..=8/self.lsb {
let shift = (self.lsb*i) as u32;
ret[n] = (ret[n] & !self.mask) |
(ch & self.mask.rotate_right(shift)).rotate_left(shift);
n += self.step;
}
}
ret
}
}
难道rustdoc测试通过有特殊规则(例如使用assert!
宏来证明它returns是一个正确的值)?
我问是因为我的方法通过了非常相似的代码的集成测试,所以我非常有信心它是正确的
这与它在 rustdoc 测试中 运行 无关。您的代码表现出未定义行为,因为它不合理。 运行 相同的代码 在测试之外 也让我感到恐慌。
您正在对内存的布局方式做出假设 - 这些假设绝不会得到任何编译器保证的支持。 "correct" 获取指针的方法是这样的:
let p = img.as_ptr() as *const u8;
然而,虽然这消除了关于 Vec
布局的假设,但代码的其余部分 仍然 假设 RGB
的布局.此更改不再让我感到恐慌,但我无法确定它是否正常工作 并且我不知道它是否会在其他计算机或我的计算机上崩溃下一次 Rust 更新。
I am asking because my method passes integration test with very similar code, so I am pretty confident it's correct
这正是 未定义行为 的危险所在,这就是为什么 unsafe
应该只用于不仅经过良好测试而且假设和保证很好理解。
我正在尝试编写名为 insert
的方法的 rustdoc 测试。
在测试的最后一行调用了测试函数,当我把它注释掉时,测试通过了。
错误信息:
$ cargo test
Compiling reproduce v0.1.0
(file:///home/user/reproduce)
Finished dev [unoptimized + debuginfo] target(s) in 2.03s
Running target/debug/deps/reproduce-17ad4bb50aa9c47e
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests reproduce
running 1 test
test src/lib.rs - MyStruct::method (line 19) ... FAILED
failures:
failures:
src/lib.rs - MyStruct::method (line 19)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
error: test failed, to rerun pass '--doc'
代码:
impl MyStruct {
pub fn new(lsb: u8, step: usize) -> MyStruct {
let mask: u8 = match lsb {
1 => 0b0000_0001,
2 => 0b0000_0011,
_ => 0b0000_1111
};
MyStruct { lsb, mask, step }
}
/// # Examples
/// ```
/// extern crate reproduce;
/// extern crate rgb;
///
/// use std::slice;
/// use rgb::RGB;
///
/// let msg = "This is a secret message".as_bytes();
/// let img = vec![RGB {r: 0, g: 0, b: 0}; 800*500];
///
/// // Create a reference to the bytes of img
/// let p: *const Vec<RGB<u8>> = &img;
/// let p: *const u8 = p as *const u8;
/// let p: &[u8] = unsafe {
/// slice::from_raw_parts(p, 3*800*500)
/// };
///
/// let settings = reproduce::MyStruct::new(2, 12);
/// let new_data = settings.method(p, &msg);
/// ```
pub fn method(&self, img: &[u8], msg: &[u8]) -> Vec<u8> {
let mut ret = img.to_vec();
let mut n = 0;
for ch in msg.iter() {
for i in 1..=8/self.lsb {
let shift = (self.lsb*i) as u32;
ret[n] = (ret[n] & !self.mask) |
(ch & self.mask.rotate_right(shift)).rotate_left(shift);
n += self.step;
}
}
ret
}
}
难道rustdoc测试通过有特殊规则(例如使用assert!
宏来证明它returns是一个正确的值)?
我问是因为我的方法通过了非常相似的代码的集成测试,所以我非常有信心它是正确的
这与它在 rustdoc 测试中 运行 无关。您的代码表现出未定义行为,因为它不合理。 运行 相同的代码 在测试之外 也让我感到恐慌。
您正在对内存的布局方式做出假设 - 这些假设绝不会得到任何编译器保证的支持。 "correct" 获取指针的方法是这样的:
let p = img.as_ptr() as *const u8;
然而,虽然这消除了关于 Vec
布局的假设,但代码的其余部分 仍然 假设 RGB
的布局.此更改不再让我感到恐慌,但我无法确定它是否正常工作 并且我不知道它是否会在其他计算机或我的计算机上崩溃下一次 Rust 更新。
I am asking because my method passes integration test with very similar code, so I am pretty confident it's correct
这正是 未定义行为 的危险所在,这就是为什么 unsafe
应该只用于不仅经过良好测试而且假设和保证很好理解。