#![no_std]
pub use mopa;
pub use paste;
#[macro_export]
macro_rules! gc_shadowstack {
($name: ident,$traceable: path,$rootable: ident,$rooted: ident,$handle: ident,$letroot: ident) => {
$crate::paste::paste!(
pub struct $name {
#[doc(hidden)]
pub head: core::cell::Cell<*mut [<Raw $name Entry>]>,
}
impl $name {
pub fn new() -> Self {
Self {
head: core::cell::Cell::new(core::ptr::null_mut())
}
}
pub unsafe fn walk(&self,mut visitor: impl FnMut(&mut dyn $rootable)) {
let mut head = *self.head.as_ptr();
while !head.is_null() {
let next = (*head).prev;
visitor((*head).get_dyn());
head = next;
}
}
}
);
$crate::paste::paste!{
#[repr(C)]
pub struct [<Raw $name Entry>] {
stack: *mut $name,
prev: *mut [<Raw $name Entry>],
vtable: usize,
data_start: [u8; 0],
}
}
pub trait $rootable: $traceable {}
$crate::paste::paste!(
impl [<Raw $name Entry>] {
pub unsafe fn get_dyn(&self) -> &mut dyn $rootable {
core::mem::transmute($crate::mopa::TraitObject {
vtable: self.vtable as _,
data: self.data_start.as_ptr() as *mut (),
})
}
}
#[repr(C)]
pub struct [<$name Internal>]<'a,T: $rootable> {
pub stack :&'a $name,
pub prev: *mut [<Raw $name Entry>],
pub vtable: usize,
pub value: T
}
impl<'a, T:$rootable> [<$name Internal>]<'a, T> {
#[inline]
pub unsafe fn construct(
stack: &'a ShadowStack,
prev: *mut [<Raw $name Entry>],
vtable: usize,
value: T,
) -> Self {
Self {
stack,
prev,
vtable,
value,
}
}
}
impl<T: $rootable> Drop for [<$name Internal>]<'_,T> {
fn drop(&mut self) {
(*self.stack).head.set(self.prev);
}
}
pub struct $rooted<'a, 'b, T: $rootable> {
#[doc(hidden)]
pinned: core::pin::Pin<&'a mut [<$name Internal>]<'b, T>>,
}
impl<'a, 'b, T: $rootable> $rooted<'a, 'b, T> {
pub unsafe fn construct(pin: core::pin::Pin<&'a mut [< $name Internal>]<'b, T>>) -> Self {
Self { pinned: pin }
}
pub unsafe fn get_internal(&self) -> &[<$name Internal>]<T> {
core::mem::transmute_copy::<_, _>(&self.pinned)
}
pub unsafe fn get_internal_mut(&mut self) -> &mut &[<$name Internal>]<T> {
core::mem::transmute_copy::<_, _>(&self.pinned)
}
pub fn mut_handle(&mut self) -> [<$handle Mut>]<'_, T> {
HandleMut { value: &mut **self }
}
pub fn handle(&self) -> $handle<'_, T> {
Handle { value: &**self }
}
}
impl<'a, T: $rootable> core::ops::Deref for $rooted<'a, '_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.pinned.value
}
}
impl<'a, T: $rootable> core::ops::DerefMut for $rooted<'a, '_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut core::mem::transmute_copy::<_, &mut [<$name Internal>]<T>>(&mut self.pinned).value
}
}
}
pub struct $handle<'a, T: $rootable> {
value: &'a T,
}
pub struct [<$handle Mut>]<'a, T: $rootable> {
value: &'a mut T,
}
impl<'a, T: $rootable> [<$handle Mut>]<'a, T> {
pub fn set(&mut self, value: T) -> T {
core::mem::replace(self.value, value)
}
}
impl<T: $rootable> core::ops::Deref for $handle<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
impl<T: $rootable> core::ops::Deref for [<$handle Mut>]<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
impl<T: $rootable> core::ops::DerefMut for [<$handle Mut>]<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.value
}
}
#[macro_export]
macro_rules! $letroot {
($var_name: ident: $t: ty = $stack: expr,$value: expr) => {
let stack: &$name = &$stack;
let value = $value;
let mut $var_name = unsafe {
[<$name Internal>]::<$t>::construct(
stack,
stack.head.get(),
core::mem::transmute::<_, $crate::mopa::TraitObject>(&value as &dyn $rootable)
.vtable as usize,
value,
)
};
stack.head.set(unsafe { core::mem::transmute(&mut $var_name) });
#[allow(unused_mut)]
let mut $var_name =
unsafe { $rooted::construct(std::pin::Pin::new(&mut $var_name)) };
};
($var_name : ident = $stack: expr,$value: expr) => {
let stack: &$name = &$stack;
let value = $value;
let mut $var_name = unsafe {
[<$name Internal>]::<_>::construct(
stack,
stack.head.get(),
core::mem::transmute::<_, $crate::mopa::TraitObject>(&value as &dyn $rootable)
.vtable as usize,
value,
)
};
stack.head.set(unsafe { core::mem::transmute(&mut $var_name) });
#[allow(unused_mut)]
let mut $var_name =
unsafe { $rooted::construct(core::pin::Pin::new(&mut $var_name)) };
};
}
);
};
}
#[cfg(doc)]
pub mod dummy {
pub trait Traceable {}
gc_shadowstack!(
ShadowStack,
Traceable,
Rootable,
Rooted,
Handle,
dummy_letroot
);
}