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() {}