[][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和LinkedList源码中也有相关的实践

#![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