sui_rust/ch02/
s9_unsafe_rust.rs

1//! 第二章:Rust核心概念
2//! 2.8 Unsafe Rust
3//!
4//! 内容包括:
5//!
6//! - 什么是 Unsafe Rust ?
7//!     
8//! - Unsafe Rust 安全抽象
9//!     - drop 检查
10//!     - Unbound Lifetime
11//!     - 型变
12//!
13//! - 标准库 [LinkedList 源码](https://doc.rust-lang.org/stable/src/alloc/collections/linked_list.rs.html#38-43)导读
14//!
15//!  - Unsafe 工具集介绍
16
17/**
18
19    # Unsafe Rust 介绍
20
21    示例1: Unsafe Rust 是 Safe Rust 的超集
22
23    ```rust
24        fn main(){
25            unsafe {
26                let mut a = "hello";
27                let b = &a;
28                let c = &mut a;
29            }
30        }
31    ```
32
33  Unsafe Rust是指,在进行以下五种操作的时候,并不会提供任何安全检查:
34
35    - 解引用裸指针。
36    - 调用unsafe的函数或方法。
37    - 访问或修改可变静态变量。
38    - 实现unsafe trait。
39    - 读写Union联合体中的字段。
40
41    解引用裸指针
42
43    - Rust提供了*const T(不变)和*mut T(可变)两种指针类型。因为这两种指针和C语言中的指针十分相近,所以叫其原生指针(Raw Pointer)。
44
45    原生指针具有以下特点:
46    - 并不保证指向合法的内存。比如很可能是一个空指针。
47    - 不能像智能指针那样自动清理内存。需要像C语言那样手动管理内存。
48    - 没有生命周期的概念,也就是说,编译器不会对其提供借用检查。
49    - 不能保证线程安全。
50
51     可见,原生指针并不受Safe Rust提供的那一层“安全外衣”保护,所以也被称为“裸指针”。所以,在对裸指针进行解引用操作的时候,属于不安全行为。
52
53
54    Unsafe语法
55
56    通过unsafe关键字和unsafe块就可以使用Unsafe Rust,它们的作用如下:
57
58    - unsafe关键字,用于标记(或者说声明)函数、方法和trait。
59    - unsafe块,用于执行Unsafe Rust允许的五种操作。
60
61    查看标准库String中的 unsafe 函数[from_utf8_unchecked](https://doc.rust-lang.org/stable/std/str/fn.from_utf8_unchecked.html),看看为什么是Unsafe的。
62
63    这里最大的风险在于,如果一个函数存在违反“契约”的风险,而开发者并没有使用unsafe关键字将其标记,那该函数就很可能会成为Bug的温床。
64    被unsafe关键字标记的不安全函数或方法,只能在unsafe块中被调用。
65
66
67
68    示例2:
69
70    ```rust
71    static mut COUNTER: u32 = 0;
72    fn main() {
73        let inc = 3;
74        unsafe {
75            COUNTER += inc;
76            println!("COUNTER: {}", COUNTER);
77        }
78    }
79    ```
80
81    Safe Rust 是基于很多 Unsafe Rust 实现的,那么 Safe Rust 凭什么 Safe ?
82
83*/
84pub fn unsafe_intro() {}
85
86/**
87
88    # 安全抽象
89
90    什么叫安全抽象? 最简单的示例:
91
92    ```rust
93    fn unbound_lifetime_foo<'a>(input: *const u32) -> &'a u32 {
94        unsafe {
95            return &*input
96        }
97    }
98
99    fn normal_foo<'a>(input: &'a u32) -> &'a u32 {
100        &input
101
102    }
103
104    fn main() {
105        let x;
106        { // -----------------------------------------------------------------------------------  `y` lifetime start
107            // unbound lifetime broken lifetime
108            let y = 7;
109            x = unbound_lifetime_foo(&y);
110
111            // normal lifetime will error: error[E0597]: `y` does not live long enough
112            // let y = 8;
113            // x = normal_foo(&y);
114        } // ----------------------------------------------------------------------------------- `y` lifetime end
115        println!("hello: {}", x);
116    }
117    ```
118
119    示例2:
120
121    ```rust
122    pub fn insert(&mut self, index: usize, element: T) {
123        let len = self.len();
124        // 通过该断言保证了数组不能越界
125        assert!(index <= len);
126        // 通过判断长度是否达到容量极限来决定是否进行扩容
127        if len == self.buf.cap() {
128            self.reserve(1);
129        }
130        unsafe {
131            {
132                let p = self.as_mut_ptr().offset(index as isize);
133                ptr::copy(p, p.offset(1), len - index);
134                ptr::write(p, element);
135            }
136            self.set_len(len + 1);
137        }
138    }
139    ```
140
141
142    ### Drop check
143
144    示例1:正常的drop check
145
146    ```rust
147    #![allow(unused)]
148    #![allow(unused)]
149    #![feature(alloc_layout_extra)]
150    #![feature(dropck_eyepatch)]
151    use std::alloc::{GlobalAlloc, Layout, System};
152    use std::fmt;
153    use std::marker::PhantomData;
154    use std::mem;
155    use std::ptr;
156
157    #[derive(Copy, Clone, Debug)]
158
159    enum State {
160        InValid,
161        Valid,
162    }
163
164    #[derive(Debug)]
165    struct Hello<T: fmt::Debug>(&'static str, T, State);
166    impl<T: fmt::Debug> Hello<T> {
167        fn new(name: &'static str, t: T) -> Self {
168            Hello(name, t, State::Valid)
169        }
170    }
171    impl<T: fmt::Debug> Drop for Hello<T> {
172        fn drop(&mut self) {
173            println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2);
174            self.2 = State::InValid;
175        }
176    }
177    struct WrapBox<T> {
178        v: Box<T>,
179    }
180    impl<T> WrapBox<T> {
181        fn new(t: T) -> Self {
182            WrapBox { v: Box::new(t) }
183        }
184    }
185    fn f1() {
186        let x;
187        let y;
188        x = Hello::new("x", 13);
189        y = WrapBox::new(Hello::new("y", &x));
190    }
191
192    struct MyBox<T> {
193        v: *const T,
194    }
195    impl<T> MyBox<T> {
196        fn new(t: T) -> Self {
197            unsafe {
198                let p = System.alloc(Layout::array::<T>(1).unwrap());
199                let p = p as *mut T;
200                ptr::write(p, t);
201                MyBox {
202                    v: p,
203                }
204            }
205        }
206    }
207
208
209    impl< T> Drop for MyBox<T> {
210        fn drop(&mut self) {
211            unsafe {
212                let p = self.v as *mut _;
213                System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap());
214            }
215        }
216    }
217
218
219    fn f2() {
220        {
221            let (x1, y1);
222            x1 = Hello::new("x1", 13);
223            y1 = MyBox::new(Hello::new("y1", &x1));
224        }
225        {
226            let (y2,x2 ); // 此处交换,会报错,注意编译错误
227            x2 = Hello::new("x2", 13);
228            y2 = MyBox::new(Hello::new("y2", &x2));
229        }
230    }
231
232    fn main() {
233        f1();
234        f2();
235    }
236
237    ```
238
239    使用 改进:
240
241    ```rust
242    #![allow(unused)]
243    #![allow(unused)]
244    #![feature(alloc_layout_extra)]
245    #![feature(dropck_eyepatch)]
246    use std::alloc::{GlobalAlloc, Layout, System};
247    use std::fmt;
248    use std::marker::PhantomData;
249    use std::mem;
250    use std::ptr;
251
252    #[derive(Copy, Clone, Debug)]
253
254    enum State {
255        InValid,
256        Valid,
257    }
258
259    #[derive(Debug)]
260    struct Hello<T: fmt::Debug>(&'static str, T, State);
261    impl<T: fmt::Debug> Hello<T> {
262        fn new(name: &'static str, t: T) -> Self {
263            Hello(name, t, State::Valid)
264        }
265    }
266    impl<T: fmt::Debug> Drop for Hello<T> {
267        fn drop(&mut self) {
268            println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2);
269            self.2 = State::InValid;
270        }
271    }
272    struct WrapBox<T> {
273        v: Box<T>,
274    }
275    impl<T> WrapBox<T> {
276        fn new(t: T) -> Self {
277            WrapBox { v: Box::new(t) }
278        }
279    }
280    fn f1() {
281        let x;
282        let y;
283        x = Hello::new("x", 13);
284        y = WrapBox::new(Hello::new("y", &x));
285    }
286
287    struct MyBox<T> {
288        v: *const T,
289    }
290    impl<T> MyBox<T> {
291        fn new(t: T) -> Self {
292            unsafe {
293                let p = System.alloc(Layout::array::<T>(1).unwrap());
294                let p = p as *mut T;
295                ptr::write(p, t);
296                MyBox {
297                    v: p,
298                }
299            }
300        }
301    }
302
303
304    unsafe impl<#[may_dangle] T> Drop for MyBox<T> {
305        fn drop(&mut self) {
306            unsafe {
307                let p = self.v as *mut _;
308                System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap());
309            }
310        }
311    }
312
313    fn f2() {
314        {
315            let (x1, y1);
316            x1 = Hello::new("x1", 13);
317            y1 = MyBox::new(Hello::new("y1", &x1));
318        }
319        {
320            let (y2,x2 ); // 此处改变
321            x2 = Hello::new("x2", 13);
322            y2 = MyBox::new(Hello::new("y2", &x2));
323        }
324    }
325
326    fn main() {
327        f1();
328        f2();
329    }
330
331    ```
332
333    使用 PhantomData 防止出现 UB:
334
335    ```rust
336    #![allow(unused)]
337    #![allow(unused)]
338    #![feature(alloc_layout_extra)]
339    #![feature(dropck_eyepatch)]
340    use std::alloc::{GlobalAlloc, Layout, System};
341    use std::fmt;
342    use std::marker::PhantomData;
343    use std::mem;
344    use std::ptr;
345
346    #[derive(Copy, Clone, Debug)]
347
348    enum State {
349        InValid,
350        Valid,
351    }
352
353    #[derive(Debug)]
354    struct Hello<T: fmt::Debug>(&'static str, T, State);
355    impl<T: fmt::Debug> Hello<T> {
356        fn new(name: &'static str, t: T) -> Self {
357            Hello(name, t, State::Valid)
358        }
359    }
360    impl<T: fmt::Debug> Drop for Hello<T> {
361        fn drop(&mut self) {
362            println!("drop Hello({}, {:?}, {:?})", self.0, self.1, self.2);
363            self.2 = State::InValid;
364        }
365    }
366    struct WrapBox<T> {
367        v: Box<T>,
368    }
369    impl<T> WrapBox<T> {
370        fn new(t: T) -> Self {
371            WrapBox { v: Box::new(t) }
372        }
373    }
374    fn f1() {
375        let x;
376        let y;
377        x = Hello::new("x", 13);
378        y = WrapBox::new(Hello::new("y", &x));
379    }
380
381    struct MyBox<T> {
382        v: *const T,
383        // _pd: PhantomData<T>,
384    }
385    impl<T> MyBox<T> {
386        fn new(t: T) -> Self {
387            unsafe {
388                let p = System.alloc(Layout::array::<T>(1).unwrap());
389                let p = p as *mut T;
390                ptr::write(p, t);
391                MyBox {
392                    v: p,
393                    // _pd: Default::default()
394                }
395            }
396        }
397    }
398
399
400    unsafe impl<#[may_dangle] T> Drop for MyBox<T> {
401        fn drop(&mut self) {
402            unsafe {
403                ptr::read(self.v); // 此处新增,出现UB (use after free,UAF)
404                let p = self.v as *mut _;
405                System.dealloc(p, Layout::array::<T>(mem::align_of::<T>()).unwrap());
406            }
407        }
408    }
409
410    fn f2() {
411        {
412            let (x1, y1);
413            x1 = Hello::new("x1", 13);
414            y1 = MyBox::new(Hello::new("y1", &x1));
415        }
416        {
417            let (y2,x2 ); // 此处改变
418            x2 = Hello::new("x2", 13);
419            y2 = MyBox::new(Hello::new("y2", &x2));
420        }
421    }
422
423    fn main() {
424        f1();
425        f2();
426    }
427
428    ```
429
430
431
432    示例:型变
433
434    在一门程序设计语言的类型系统中,一个类型规则或者类型构造器是:
435
436    - 协变(covariant),如果它保持了子类型序关系≦。该序关系是:子类型≦基类型。
437    - 逆变(contravariant),如果它逆转了子类型序关系。
438    - 不变(invariant),如果上述两种均不适用。
439
440    Rust 里唯一的类型父子关系是生命周期:`'a: 'b` 。比如,`'static: 'a` ,并且默认都是协变,唯一逆变的地方在 `fn(T)`
441
442    `'static: 'a` 对应: `子类型: 父类型`。
443
444    - 协变: 能用 'a 的地方,也可以用 'static。
445    - 逆变: 能用 'static 的地方,可以可以用 'a。
446
447    规则:
448
449    PhantomData规则:
450
451    - PhantomData,在T上是协变。
452    - PhantomData<&'a T>,在'a 和T上是协变。
453    - PhantomData<&'a mut T>,在'a上是协变,在T上是不变。
454    - PhantomData<*const T>,在T上是协变。
455    - PhantomData<*mut T>,在T上不变。
456    - PhantomData<fn(T)>,在T上是逆变,如果以后语法修改的话,会成为不变。
457    - PhantomData<fn() -> T>,在T上是协变。
458    - PhantomData<fn(T) -> T>,在T上是不变。
459    - PhantomData<Cell<&'a ()>>,在'a上是不变。
460
461    ```rust
462    // 协变类型
463    struct MyCell<T> {
464        value: T,
465    }
466    impl<T: Copy> MyCell<T> {
467        fn new(x: T) -> MyCell<T> {
468            MyCell { value: x }
469        }
470        fn get(&self) -> T {
471            self.value
472    }
473    fn set(&self, value: T) {
474        use std::ptr;
475        unsafe {
476            ptr::write(&self.value as *const _ as *mut _, value);
477        }
478    }
479    }
480
481    fn step1<'a>(r_c1: &MyCell<&'a i32>) {
482        let val: i32 = 13;
483        step2(&val, r_c1); // step2函数执行完再回到step1
484        println!("step1 value: {}", r_c1.value);
485    } // step1调用完,栈帧将被清理,val将不复存在,&val将成为悬垂指针
486
487    fn step2<'b>(r_val: &'b i32, r_c2: &MyCell<&'b i32>) {
488        r_c2.set(r_val);
489    }
490    static X: i32 = 10;
491    fn main() {
492    let cell = MyCell::new(&X);
493    step1(&cell);
494    println!("  end value: {}", cell.value); //此处 cell.value的值将无法预期,UB风险
495    }
496
497    ```
498
499    Basic usage: 修改MyCell 类型为不变
500
501    解决上面示例UB的问题,编译将报错,因为安全检查生效了,成功阻止了UB风险
502
503    ```rust
504    use std::marker::PhantomData;
505    struct MyCell<T> {
506        value: T,
507        mark: PhantomData<fn(T)> , //通过PhantomData<fn(T)>将MyCell<T>改为逆变类型
508    }
509    impl<T: Copy> MyCell<T> {
510        fn new(x: T) -> MyCell<T> {
511            MyCell { value: x , mark: PhantomData}
512        }
513    fn get(&self) -> T {
514        self.value
515    }
516    fn set(&self, value: T) {
517        use std::ptr;
518        unsafe {
519            ptr::write(&self.value as *const _ as *mut _, value);
520        }
521    }
522    }
523    fn step1<'a>(r_c1: &MyCell<&'a i32>) {
524        let val: i32 = 13;
525        step2(&val, r_c1); // error[E0597]: `val` does not live long enough
526        println!("step1 value: {}", r_c1.value);
527    } // step1调用完,栈帧将被清理,val将不复存在,&val将成为悬垂指针
528
529    fn step2<'b>(r_val: &'b i32, r_c2: &MyCell<&'b i32>) {
530        r_c2.set(r_val);
531    }
532    static X: i32 = 10;
533    fn main() {
534        let cell = MyCell::new(&X);
535        step1(&cell);
536        println!("  end value: {}", cell.value);
537    }
538    ```
539
540    示例:逆变
541
542    ```rust
543    #![allow(unused)]
544    trait A {
545        fn foo(&self, s: &'static str);
546    }
547    struct B;
548    impl A for B {
549        fn foo(&self, s: &str){
550            println!("{:?}", s);
551        }
552    }
553    impl B{
554    fn foo2(&self, s: &'static str){
555        println!("{:?}", s);
556    }
557    }
558    fn main() {
559        B.foo("hello");
560        let s = "hello".to_string();
561        B.foo2(&s)
562    }
563
564    ```
565
566    示例2:
567
568    ```rust
569    fn foo(input: &str)  {
570        println!("{:?}", input);
571    }
572    fn bar(f: fn(&'static str), v: &'static str) {
573        (f)(v);
574    }
575    fn main(){
576        let v : &'static str = "hello";
577        bar(foo, v);
578    }
579    ```
580
581*/
582pub fn security_abstract() {}
583
584/**
585
586    # 其他介绍
587
588    - [NonNull](https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html)
589    - [Play](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=d95a1c5ec1a8c4279f366bb044ad6202)
590    - [LinkedList](https://doc.rust-lang.org/nightly/src/alloc/collections/linked_list.rs.html#39-44)
591    - [MaybeUninit](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html)
592    - 推荐阅读:[Unsafe Rust: How and when (not) to use it](https://blog.logrocket.com/unsafe-rust-how-and-when-not-to-use-it/)
593    - [rustsec advisories](https://rustsec.org/advisories/)
594*/
595pub fn nonnull() {}