今天在用Rust写DragonOS的signal机制时候,遇到了这么一个问题:我需要在fork的时候为进程动态分配sighand结构体,而直接使用Box::new()出来的sighand对象,在process_copy_sighand()函数结束之后,生命周期就结束了,rust编译器会自动调用它的drop()方法。而我希望这个对象能够一直存活(不然的话怎么放到pcb里面哈哈哈),因此需要将其生命周期转换为static的。
先看看错误的代码:
我们在第27行动态申请了一块内存,用来放置sighand_struct, 然后想要在第30、31行处把它赋值给pcb的sighand指针字段。
乍一看好像没有问题,编译也是可以通过的。但是,我们要注意,这里涉及到的pcb以及它里面的指针字段,是raw pointer,rust的编译器只会对它进行基本的检查,而不会进行生命周期检查。而且给pcb的sighand字段赋值的过程,是在unsafe块中的。
由于sig变量的生命周期只是在这个process_copy_sighand函数内,因此当这个函数return之后,sig变量将会被drop,于是pcb内部的sighand指针就成了一个悬垂指针,从而产生use-after-free问题。
为了解决这个问题,我们需要将sig变量的生命周期变为static的,从而使得它不会在函数返回后被释放。
我们可以使用Box::leak()函数来达成这个目的。这个函数能够取出上面的第27行分配得到的box内的sighand_struct, 并将其设置为static的生命周期。这样就能够达到我们的目的了。
修改之后的代码长这个样子:
上图第31行将new之后得到的box传入Box::leak(),得到一个static生命周期的&mut sighand_struct,然后我们再将这个sighand_struct传入pcb的sighand字段即可。当然,我们也需要在相应的exit函数内部释放这个变量,否则将会造成内存泄露。