修正rwlock有的地方由于未使用ManuallyDrop导致的use after free && spinlock守卫新增leak,spinlock新增force unlock功能.(#329)

1.修正rwlock有的地方由于未使用ManuallyDrop导致的use after free
2. spinlock守卫新增leak,spinlock新增force unlock功能.
This commit is contained in:
LoGin 2023-08-14 01:24:49 +08:00 committed by GitHub
parent c3dad0011d
commit 90a0a49048
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 9 deletions

View File

@ -292,12 +292,19 @@ impl<T> From<T> for RwLock<T> {
} }
impl<'rwlock, T> RwLockReadGuard<'rwlock, T> { impl<'rwlock, T> RwLockReadGuard<'rwlock, T> {
/// @brief 释放守卫,获得保护的值的不可变引用
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放从而导致pcb的preempt count不正确
/// 因此必须小心的手动维护好preempt count。
///
/// 并且leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
#[allow(dead_code)] #[allow(dead_code)]
#[inline] #[inline]
/// @brief 释放守卫,获得保护的值的不可变引用 pub unsafe fn leak(this: Self) -> &'rwlock T {
pub fn leak(this: Self) -> &'rwlock T { let this = ManuallyDrop::new(this);
let Self { data, .. } = this; return unsafe { &*this.data };
return unsafe { &*data };
} }
} }
@ -363,9 +370,16 @@ impl<'rwlock, T> RwLockUpgradableGuard<'rwlock, T> {
#[allow(dead_code)] #[allow(dead_code)]
#[inline] #[inline]
/// @brief 返回内部数据的引用,消除锁 /// @brief 返回内部数据的引用,消除守卫
pub fn leak(this: Self) -> &'rwlock T { ///
let this = ManuallyDrop::new(this); /// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放从而导致pcb的preempt count不正确
/// 因此必须小心的手动维护好preempt count。
///
/// 并且leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
pub unsafe fn leak(this: Self) -> &'rwlock T {
let this: ManuallyDrop<RwLockUpgradableGuard<'_, T>> = ManuallyDrop::new(this);
unsafe { &*this.data } unsafe { &*this.data }
} }
@ -374,8 +388,15 @@ impl<'rwlock, T> RwLockUpgradableGuard<'rwlock, T> {
impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> { impl<'rwlock, T> RwLockWriteGuard<'rwlock, T> {
#[allow(dead_code)] #[allow(dead_code)]
#[inline] #[inline]
/// @brief 返回内部数据的引用,消除锁 /// @brief 返回内部数据的引用,消除守卫
pub fn leak(this: Self) -> &'rwlock T { ///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放从而导致pcb的preempt count不正确
/// 因此必须小心的手动维护好preempt count。
///
/// 并且leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
pub unsafe fn leak(this: Self) -> &'rwlock T {
let this = ManuallyDrop::new(this); let this = ManuallyDrop::new(this);
return unsafe { &*this.data }; return unsafe { &*this.data };

View File

@ -1,5 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::ptr::read_volatile; use core::ptr::read_volatile;
@ -107,6 +108,11 @@ impl RawSpinlock {
self.0.store(false, Ordering::Release); self.0.store(false, Ordering::Release);
} }
/// 解锁但是不更改preempt count
unsafe fn unlock_no_preempt(&self) {
self.0.store(false, Ordering::Release);
}
/// @brief 放锁并开中断 /// @brief 放锁并开中断
pub fn unlock_irq(&self) { pub fn unlock_irq(&self) {
self.unlock(); self.unlock();
@ -170,6 +176,24 @@ pub struct SpinLockGuard<'a, T: 'a> {
flag: usize, flag: usize,
} }
impl<'a, T: 'a> SpinLockGuard<'a, T> {
/// 泄露自旋锁的守卫,返回一个可变的引用
///
/// ## Safety
///
/// 由于这样做可能导致守卫在另一个线程中被释放从而导致pcb的preempt count不正确
/// 因此必须小心的手动维护好preempt count。
///
/// 并且leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
#[inline]
pub unsafe fn leak(this: Self) -> &'a mut T {
// Use ManuallyDrop to avoid stacked-borrow invalidation
let this = ManuallyDrop::new(this);
// We know statically that only we are referencing data
unsafe { &mut *this.lock.data.get() }
}
}
/// 向编译器保证SpinLock在线程之间是安全的. /// 向编译器保证SpinLock在线程之间是安全的.
/// 其中要求类型T实现了Send这个Trait /// 其中要求类型T实现了Send这个Trait
unsafe impl<T> Sync for SpinLock<T> where T: Send {} unsafe impl<T> Sync for SpinLock<T> where T: Send {}
@ -223,6 +247,16 @@ impl<T> SpinLock<T> {
} }
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
} }
/// 强制解锁并且不更改preempt count
///
/// ## Safety
///
/// 由于这样做可能导致preempt count不正确因此必须小心的手动维护好preempt count。
/// 如非必要,请不要使用这个函数。
pub unsafe fn force_unlock(&self) {
self.lock.unlock_no_preempt();
}
} }
/// 实现Deref trait支持通过获取SpinLockGuard来获取临界区数据的不可变引用 /// 实现Deref trait支持通过获取SpinLockGuard来获取临界区数据的不可变引用