[−][src]Function tao_of_rust::ch13::security_abstract::drop_ck_test
pub fn drop_ck_test()
Drop检查
使用不当的话,Drop检查会引起UB
Basic usage: 声明元组变量测试dropck
在Safe Rust中由dropck引起的问题,借用检查会安全识别,从而引起错误阻止程序编译
use std::fmt; #[derive(Copy, Clone, Debug)] enum State { InValid, Valid } #[derive(Debug)] struct Hello<T: fmt::Debug>(&'static str, T, State); impl<T: fmt::Debug> Hello<T> { fn new(name: &'static str, t: T) -> Self { Hello(name, t, State::Valid) } } impl<T: fmt::Debug> Drop for Hello<T> { fn drop(&mut self) { println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2); self.2 = State::InValid; } } struct WrapBox<T> { v: Box<T>, } impl<T> WrapBox<T> { fn new(t: T) -> Self { WrapBox { v: Box::new(t) } } } fn f1() { // let x; let y; // 使用此注释的x和y声明顺序即可解决问题 let (x, y); x = Hello::new("x", 13); // error[E0597]: `x` does not live long enough y = WrapBox::new(Hello::new("y", &x)); } fn main() { f1(); }Run
Basic usage: dropck
- V1
会因为安全检查而报错,修改变量声明顺序修复问题
#![feature(alloc_layout_extra)] #![feature(allocator_api, dropck_eyepatch)] use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr; use std::mem; use std::fmt; #[derive(Copy, Clone, Debug)] enum State { InValid, Valid } #[derive(Debug)] struct Hello<T: fmt::Debug>(&'static str, T, State); impl<T: fmt::Debug> Hello<T> { fn new(name: &'static str, t: T) -> Self { Hello(name, t, State::Valid) } } impl<T: fmt::Debug> Drop for Hello<T> { fn drop(&mut self) { println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2); self.2 = State::InValid; } } struct WrapBox<T> { v: Box<T>, } impl<T> WrapBox<T> { fn new(t: T) -> Self { WrapBox { v: Box::new(t) } } } fn f1() { // let x; let y; // 使用此注释的x和y声明顺序即可解决问题 let (x, y); x = Hello::new("x", 13); // error[E0597]: `x` does not live long enough y = WrapBox::new(Hello::new("y", &x)); } struct MyBox<T> { v: *const T, } impl<T> MyBox<T> { fn new(t: T) -> Self { unsafe { let p = System.alloc(Layout::array::<T>(1).unwrap()); let p = p as *mut T; ptr::write(p, t); MyBox { v: p } } } } impl<T> Drop for MyBox<T> { fn drop(&mut self) { unsafe { let p = self.v as *mut _; System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap()); } } } fn f2() { { let (x1, y1); x1 = Hello::new("x1", 13); y1 = MyBox::new(Hello::new("y1", &x1)); } { let (x2, y2); x2 = Hello::new("x2", 13); y2 = MyBox::new(Hello::new("y2", &x2)); } } fn main() { // f1(); f2(); }Run
Basic usage: #[may_dangle]
属性与dropck
- V2
通过 #[may_dangle]
修复问题
#![feature(alloc_layout_extra)] #![feature(allocator_api, dropck_eyepatch)] use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr; use std::mem; use std::fmt; #[derive(Copy, Clone, Debug)] enum State { InValid, Valid } #[derive(Debug)] struct Hello<T: fmt::Debug>(&'static str, T, State); impl<T: fmt::Debug> Hello<T> { fn new(name: &'static str, t: T) -> Self { Hello(name, t, State::Valid) } } impl<T: fmt::Debug> Drop for Hello<T> { fn drop(&mut self) { println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2); self.2 = State::InValid; } } struct WrapBox<T> { v: Box<T>, } impl<T> WrapBox<T> { fn new(t: T) -> Self { WrapBox { v: Box::new(t) } } } fn f1() { let x; let y; x = Hello::new("x", 13); y = WrapBox::new(Hello::new("y", &x)); } struct MyBox<T> { v: *const T, } impl<T> MyBox<T> { fn new(t: T) -> Self { unsafe { let p = System.alloc(Layout::array::<T>(1).unwrap()); let p = p as *mut T; ptr::write(p, t); MyBox { v: p } } } } // 使用#[may_dangle]来修复问题 unsafe impl<#[may_dangle] T> Drop for MyBox<T> { fn drop(&mut self) { unsafe { let p = self.v as *mut _; System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap()); } } } fn f2() { { let (x1, y1); x1 = Hello::new("x1", 13); y1 = MyBox::new(Hello::new("y1", &x1)); } { let (x2, y2); x2 = Hello::new("x2", 13); y2 = MyBox::new(Hello::new("y2", &x2)); } } fn main() { // f1(); f2(); }Run
Basic usage: #[may_dangle]
属性与dropck
- V3
通过 #[may_dangle]
修复问题,但如果在drop中使用了T,则会产生悬垂指针
#![feature(alloc_layout_extra)] #![feature(allocator_api, dropck_eyepatch)] use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr; use std::mem; use std::fmt; #[derive(Copy, Clone, Debug)] enum State { InValid, Valid } #[derive(Debug)] struct Hello<T: fmt::Debug>(&'static str, T, State); impl<T: fmt::Debug> Hello<T> { fn new(name: &'static str, t: T) -> Self { Hello(name, t, State::Valid) } } impl<T: fmt::Debug> Drop for Hello<T> { fn drop(&mut self) { println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2); self.2 = State::InValid; } } struct WrapBox<T> { v: Box<T>, } impl<T> WrapBox<T> { fn new(t: T) -> Self { WrapBox { v: Box::new(t) } } } fn f1() { let x; let y; x = Hello::new("x", 13); y = WrapBox::new(Hello::new("y", &x)); } struct MyBox<T> { v: *const T, } impl<T> MyBox<T> { fn new(t: T) -> Self { unsafe { let p = System.alloc(Layout::array::<T>(1).unwrap()); let p = p as *mut T; ptr::write(p, t); MyBox { v: p } } } } // 使用#[may_dangle]来修复问题 unsafe impl<#[may_dangle] T> Drop for MyBox<T> { fn drop(&mut self) { unsafe { ptr::read(self.v); // 此处新增 let p = self.v as *mut _; System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap()); } } } fn f2() { { let (x1, y1); x1 = Hello::new("x1", 13); y1 = MyBox::new(Hello::new("y1", &x1)); } { let (y2, x2); // 此处改变 x2 = Hello::new("x2", 13); y2 = MyBox::new(Hello::new("y2", &x2)); } } fn main() { // f1(); f2(); }Run
Basic usage: #[may_dangle]
属性 与dropck
- V4
使用PhantomData<T>
配合#[may_dangle]
来得到更严格的drop检查
标准库中Vec
#![feature(alloc_layout_extra)] #![feature(allocator_api, dropck_eyepatch)] use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr; use std::mem; use std::fmt; use std::marker::PhantomData; #[derive(Copy, Clone, Debug)] enum State { InValid, Valid } #[derive(Debug)] struct Hello<T: fmt::Debug>(&'static str, T, State); impl<T: fmt::Debug> Hello<T> { fn new(name: &'static str, t: T) -> Self { Hello(name, t, State::Valid) } } impl<T: fmt::Debug> Drop for Hello<T> { fn drop(&mut self) { println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2); self.2 = State::InValid; } } struct WrapBox<T> { v: Box<T>, } impl<T> WrapBox<T> { fn new(t: T) -> Self { WrapBox { v: Box::new(t) } } } fn f1() { let x; let y; x = Hello::new("x", 13); y = WrapBox::new(Hello::new("y", &x)); } struct MyBox<T> { v: *const T, } impl<T> MyBox<T> { fn new(t: T) -> Self { unsafe { let p = System.alloc(Layout::array::<T>(1).unwrap()); let p = p as *mut T; ptr::write(p, t); MyBox { v: p } } } } // 使用#[may_dangle]来修复问题 unsafe impl<#[may_dangle] T> Drop for MyBox<T> { fn drop(&mut self) { unsafe { ptr::read(self.v); // 此处新增 let p = self.v as *mut _; System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap()); } } } fn f2() { { let (x1, y1); x1 = Hello::new("x1", 13); y1 = MyBox::new(Hello::new("y1", &x1)); } { let (y2, x2); // 此处改变 x2 = Hello::new("x2", 13); y2 = MyBox::new(Hello::new("y2", &x2)); } } struct MyBox2<T> { v: *const T, _pd: PhantomData<T>, } impl<T> MyBox2<T> { fn new(t: T) -> Self { unsafe{ let p = System.alloc(Layout::array::<T>(1).unwrap()); let p = p as *mut T; ptr::write(p, t); MyBox2 { v: p, _pd: Default::default() } } } } unsafe impl<#[may_dangle] T> Drop for MyBox2<T> { fn drop(&mut self) { unsafe { ptr::read(self.v); let p = self.v as *mut _; System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap()); } } } fn f3() { // let (y, x); // let (x, y); let x; let y; x = Hello::new("x", 13); y = MyBox2::new(Hello::new("y", &x)); } fn main() { // f1(); // f2(); f3(); }Run