fn main() {
let result_ref;
{
let num1 = 1;
let num2 = 2;
let arg1 = &num1;
{
let arg2 = &num2;
result_ref = snd(arg1, arg2);
println!("{}", result_ref);
}
}
}
fn snd<'a>(_x: &i32, y: &'a i32) -> &'a i32 {
y
}
正常编译,输出2
fn main() {
let result_ref;
{
let num1 = 1;
let num2 = 2;
let arg1 = &num1;
{
let arg2 = &num2;
result_ref = snd(arg1, arg2);
}
println!("{}", result_ref);
}
}
fn snd<'a>(_x: &i32, y: &'a i32) -> &'a i32 {
y
}
仍然正常编译,输出2,生命周期和 arg2 绑定的作用域无关,因为 arg2 持有的引用指向实际的值 num2,而 num2 此时并没有离开作用域,此时 result_ref 对于 num2 的引用仍然是合法的。
生命周期与持有引用的变量本身的作用域无关
fn main() {
let result_ref;
{
let num1 = 1;
let num2 = 2;
let arg1 = &num1;
{
let arg2 = &num2;
result_ref = snd(arg1, arg2);
}
}
println!("{}", result_ref); // UAF occurs here
}
fn snd<'a>(_x: &i32, y: &'a i32) -> &'a i32 {
y
}
error[E0597]: `num2` does not live long enough
--> .\test.rs:8:24
|
5 | let num2 = 2;
| ---- binding `num2` declared here
...
8 | let arg2 = &num2;
| ^^^^^ borrowed value does not live long enough
...
11 | }
| - `num2` dropped here while still borrowed
12 | println!("{}", result_ref); // UAF occurs here
| ---------- borrow later used here
error: aborting due to 1 previous error
此时 num2 已经离开作用域被释放,而 result_ref 仍然保留对 num2 的引用,构成 Use-after-free,所以无法编译。
fn main() {
let result_ref;
{
let num2 = 2;
{
let num1 = 1;
result_ref = snd(&num1, &num2);
}
println!("{}", result_ref);
}
}
fn snd<'a, 'b>(_x: &'a i32, y: &'b i32) -> &'b i32 {
y
}
正常编译
fn main() {
let result_ref;
{
let num1 = 1;
{
let num2 = 2;
result_ref = snd(&num1, &num2);
}
println!("{}", result_ref);
}
}
fn snd<'a, 'b>(_x: &'a i32, y: &'b i32) -> &'b i32 {
y
}
error[E0597]: `num2` does not live long enough
--> .\test.rs:7:37
|
6 | let num2 = 2;
| ---- binding `num2` declared here
7 | result_ref = snd(&num1, &num2);
| ^^^^^ borrowed value does not live long enough
8 | }
| - `num2` dropped here while still borrowed
9 | println!("{}", result_ref);
| ---------- borrow later used here
error: aborting due to 1 previous error
同样, num2 的生命周期比持有其引用的 result_ref 要短,如果可以在 num2 的生命周期结束后使用 result_ref 会导致 UAF
fn main() {
let mut result_ref;
{
let num1 = 1;
{
let num2 = 2;
result_ref = snd(&num1, &num2);
}
result_ref = &num1;
println!("{}", result_ref);
}
}
fn snd<'a, 'b>(_x: &'a i32, y: &'b i32) -> &'b i32 {
y
}
在 num2 的生命周期结束后不使用对 num2 的引用就不会有问题