不安全的Rust

不安全的Rust拥有以下能力:

  1. 解引用裸指针
  2. 调用不安全的函数或者方法
  3. 访问或修改可变静态变量
  4. 实现不安全的trait
    这种方法不会关闭rust中的借用检查器或者禁用任何其他的rust安全检查规则,只提供上述
    几个不被编译器检查内存安全的功能,这种代码的正确与否,由程序员自己保证

解用裸指针

裸指针分为两种:

  1. 不可变裸指针:const T(这里的是const连用的,并不是解引用的*,写法就是如此)
  2. 可变裸指针: *mut T(同上)

(1) 允许忽略借用规则,可以同是拥有不可变和可变的指针,或者是多个指向相同位置的
可变指针

(2) 不保证指向的内存有效
(3) 允许为空
(4) 不能实现任何自动清理的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
let mut num = 5;
//创建不可变和可变的裸指针是可以安全在代码中,只是不能在不安全代码块之外解引用
//裸指针
let r1 = &num as *const i32; //不可变裸指针
let r1 = &num as *mut i32; //可变裸指针

//不可以在安全代码中解引用
//只能在不安全代码中解引用
//报错
//println!("r1 = {}",*r1);
//println!("r2 = {}",*r2);
unsafe {
println!("r1 = {}",*r1);
println!("r2 = {}",*r2);
}

let add = 0x12345usize; //一个地址
let r = add as *const i32;//这个内存地址可能没有在使用,在使用过程中可能会报错

}

调用不安全函数或者方法

1
2
3
4
5
6
7
8
9
10
11
unsafe fn dangerous() {
println!("do something dangerous");
}

fn main() {
unsafe {
dangerous();
}
//报错,为不安全函数
//dangerous();
}

创建不安全代码的抽象(相当于封装)

1
2
3
4
5
6
7
8
9
10
11
12
13
fn foo () {
let mut num = 5;
let r1 =&num as *const i32;
let r2 =&num as *mut i32;

unsafe {
println!("* r1 = {}",r1);
println!("* r2 = {}",r2);
}
}
fn main() {
foo();
}

调用C语言的函数

1
2
3
4
5
6
7
8
extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("abs(-3): {}",abs(-3));
}
}

C语言调用Rust

1
2
3
4
5
mkdir learn
cd learn
cargo new foo --lib
cd foo
vim src/lib.rs
  • 之后在库中填写代码
1
2
3
4
5
#![crate_type = "staticlib"]
#[no_mangle]
pub extern fn foo () {
println!("use rust");
}
  • 之后在Cargo.toml中:
1
2
3
4
[dependencies]
[lib]
name = "foo"
crate-type = ["staticlib"]
  • 之后使用cargo build
1
2
3
4
cd /learn
cd target
ls
cp libfoo.a /learn #将文件拷贝到learn中

这个时候你就可以看到libfoo.a文件

  • C语言部分
1
2
# 位置在/learn
vim main.c

之后使用:

1
2
3
4
5
extern void foo();
int main() {
foo();
return 0;
}
  • 进行编译
1
2
gcc -o main main.c libfoo.a -lpthread -ldl ## 添加weak和多线程库,不然会报错
./main

访问或者修改可变静态变量

静态变量中的值有一个固定的内存地址(使用值总会访问相同的地址),而常量则允许任何在
被用到的时候复制数据
静态变量可以是可变的,虽然可能不安全(使用unsafe包含)

1
2
3
4
5
static HELLO_WORLD: &str = "Hello World";

fn main() {
println!("{}",HELLO_WORLD);
}
  • 使用静态变量中的可变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static mut COUNTER: u32 = 0;
fn add_counter(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn main() {
add_counter(3);
add_counter(3);
unsafe {
//可变的静态变量要用unsafe模块包含
println!("counter: {}",COUNTER);
}
}

实现不安全的trait

  1. 当至少一个方法中包含编译器不能验证的变量时,该trait就是不安全的
  2. 在trait之前增加unsafe声明它是不安全的,同时trait也必须使用unsafe标记
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unsafe trait Foo {
fn foo(&self);
}

struct Bar();

unsafe impl Foo for Bar {
fn foo(&self) {
println!("foo");
}
}

fn main() {
let a = Bar();
a.foo;
}