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

View File

@ -1,5 +1,6 @@
#![allow(dead_code)]
use core::cell::UnsafeCell;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
use core::ptr::read_volatile;
@ -107,6 +108,11 @@ impl RawSpinlock {
self.0.store(false, Ordering::Release);
}
/// 解锁但是不更改preempt count
unsafe fn unlock_no_preempt(&self) {
self.0.store(false, Ordering::Release);
}
/// @brief 放锁并开中断
pub fn unlock_irq(&self) {
self.unlock();
@ -170,6 +176,24 @@ pub struct SpinLockGuard<'a, T: 'a> {
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在线程之间是安全的.
/// 其中要求类型T实现了Send这个Trait
unsafe impl<T> Sync for SpinLock<T> where T: Send {}
@ -223,6 +247,16 @@ impl<T> SpinLock<T> {
}
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来获取临界区数据的不可变引用