Skip to content

Commit

Permalink
Auto merge of #123490 - niluxv:strict_prov_unwind_seh, r=Amanieu
Browse files Browse the repository at this point in the history
Refactor `panic_unwind/seh.rs` pointer use

* `x86` now conforms to strict-provenance
* `x86_64` now uses the expose API (instead of `as` casts)
* changed `ptr_t` from a type alias to a `repr(transparent)` struct for some extra type-safety
* replaced the `ptr!` macro by methods on `ptr_t`, as there is now no reason (as far as I can see) anymore to use a macro

On `x86_64` pointers in SEH are represented by 32-bit offsets from `__ImageBase`, so we can't use a pointer type. It might be possible to leak the provenance into the FFI by using a `MaybeUninit<u32>` instead of a `u32`, but that is a bit more involved than using expose, and I'm not sure that would be worth it.
  • Loading branch information
bors committed Apr 11, 2024
2 parents f13f37f + 3d0ed4a commit be361ad
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 41 deletions.
2 changes: 2 additions & 0 deletions library/panic_unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(strict_provenance)]
#![feature(exposed_provenance)]
#![feature(rustc_attrs)]
#![panic_runtime]
#![feature(panic_runtime)]
Expand Down
104 changes: 63 additions & 41 deletions library/panic_unwind/src/seh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,58 +109,80 @@ struct Exception {
// [1]: https://www.geoffchappell.com/studies/msvc/language/predefined/

#[cfg(target_arch = "x86")]
#[macro_use]
mod imp {
pub type ptr_t = *mut u8;

macro_rules! ptr {
(0) => {
core::ptr::null_mut()
};
($e:expr) => {
$e as *mut u8
};
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ptr_t(*mut u8);

impl ptr_t {
pub const fn null() -> Self {
Self(core::ptr::null_mut())
}

pub const fn new(ptr: *mut u8) -> Self {
Self(ptr)
}
}
}

#[cfg(not(target_arch = "x86"))]
#[macro_use]
mod imp {
pub type ptr_t = u32;
use core::ptr::addr_of;

// On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`.
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ptr_t(u32);

extern "C" {
pub static __ImageBase: u8;
}

macro_rules! ptr {
(0) => (0);
($e:expr) => {
(($e as usize) - (addr_of!(imp::__ImageBase) as usize)) as u32
impl ptr_t {
pub const fn null() -> Self {
Self(0)
}

pub fn new(ptr: *mut u8) -> Self {
// We need to expose the provenance of the pointer because it is not carried by
// the `u32`, while the FFI needs to have this provenance to excess our statics.
//
// NOTE(niluxv): we could use `MaybeUninit<u32>` instead to leak the provenance
// into the FFI. In theory then the other side would need to do some processing
// to get a pointer with correct provenance, but these system functions aren't
// going to be cross-lang LTOed anyway. However, using expose is shorter and
// requires less unsafe.
let addr: usize = ptr.expose_provenance();
let image_base = unsafe { addr_of!(__ImageBase) }.addr();
let offset: usize = addr - image_base;
Self(offset as u32)
}
}
}

use imp::ptr_t;

#[repr(C)]
pub struct _ThrowInfo {
pub attributes: c_uint,
pub pmfnUnwind: imp::ptr_t,
pub pForwardCompat: imp::ptr_t,
pub pCatchableTypeArray: imp::ptr_t,
pub pmfnUnwind: ptr_t,
pub pForwardCompat: ptr_t,
pub pCatchableTypeArray: ptr_t,
}

#[repr(C)]
pub struct _CatchableTypeArray {
pub nCatchableTypes: c_int,
pub arrayOfCatchableTypes: [imp::ptr_t; 1],
pub arrayOfCatchableTypes: [ptr_t; 1],
}

#[repr(C)]
pub struct _CatchableType {
pub properties: c_uint,
pub pType: imp::ptr_t,
pub pType: ptr_t,
pub thisDisplacement: _PMD,
pub sizeOrOffset: c_int,
pub copyFunction: imp::ptr_t,
pub copyFunction: ptr_t,
}

#[repr(C)]
Expand All @@ -186,20 +208,20 @@ const TYPE_NAME: [u8; 11] = *b"rust_panic\0";

static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
attributes: 0,
pmfnUnwind: ptr!(0),
pForwardCompat: ptr!(0),
pCatchableTypeArray: ptr!(0),
pmfnUnwind: ptr_t::null(),
pForwardCompat: ptr_t::null(),
pCatchableTypeArray: ptr_t::null(),
};

static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray =
_CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr!(0)] };
_CatchableTypeArray { nCatchableTypes: 1, arrayOfCatchableTypes: [ptr_t::null()] };

static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
properties: 0,
pType: ptr!(0),
pType: ptr_t::null(),
thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
sizeOrOffset: mem::size_of::<Exception>() as c_int,
copyFunction: ptr!(0),
copyFunction: ptr_t::null(),
};

extern "C" {
Expand Down Expand Up @@ -246,9 +268,9 @@ macro_rules! define_cleanup {
super::__rust_drop_panic();
}
}
unsafe extern $abi2 fn exception_copy(_dest: *mut Exception,
_src: *mut Exception)
-> *mut Exception {
unsafe extern $abi2 fn exception_copy(
_dest: *mut Exception, _src: *mut Exception
) -> *mut Exception {
panic!("Rust panics cannot be copied");
}
}
Expand Down Expand Up @@ -296,24 +318,24 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
// In any case, we basically need to do something like this until we can
// express more operations in statics (and we may never be able to).
atomic_store_seqcst(
addr_of_mut!(THROW_INFO.pmfnUnwind) as *mut u32,
ptr!(exception_cleanup) as u32,
addr_of_mut!(THROW_INFO.pmfnUnwind).cast(),
ptr_t::new(exception_cleanup as *mut u8),
);
atomic_store_seqcst(
addr_of_mut!(THROW_INFO.pCatchableTypeArray) as *mut u32,
ptr!(addr_of!(CATCHABLE_TYPE_ARRAY)) as u32,
addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(),
ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()),
);
atomic_store_seqcst(
addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]) as *mut u32,
ptr!(addr_of!(CATCHABLE_TYPE)) as u32,
addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(),
ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()),
);
atomic_store_seqcst(
addr_of_mut!(CATCHABLE_TYPE.pType) as *mut u32,
ptr!(addr_of!(TYPE_DESCRIPTOR)) as u32,
addr_of_mut!(CATCHABLE_TYPE.pType).cast(),
ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()),
);
atomic_store_seqcst(
addr_of_mut!(CATCHABLE_TYPE.copyFunction) as *mut u32,
ptr!(exception_copy) as u32,
addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(),
ptr_t::new(exception_copy as *mut u8),
);

extern "system-unwind" {
Expand Down

0 comments on commit be361ad

Please sign in to comment.