Skip to content

Commit

Permalink
change rustc's vision of enums to avoid potential UB
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed May 3, 2024
1 parent db4aa85 commit e14810c
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 109 deletions.
2 changes: 1 addition & 1 deletion examples/dynlinkage/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#[stabby::import(name = "library")]
extern "C" {
pub fn stable_fn(v: u8);
pub fn stable_fn(v: u8) -> stabby::option::Option<()>;
}

#[stabby::import(canaries = "", name = "library")]
Expand Down
5 changes: 3 additions & 2 deletions examples/library/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
//

#[stabby::export]
pub extern "C" fn stable_fn(v: u8) {
println!("{v}")
pub extern "C" fn stable_fn(v: u8) -> stabby::option::Option<()> {
println!("{v}");
Default::default()
}

#[stabby::export(canaries)]
Expand Down
18 changes: 9 additions & 9 deletions stabby-abi/src/enums/err_non_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct Layout<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
>(
core::marker::PhantomData<(
Expand Down Expand Up @@ -89,7 +89,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
> IDeterminantProviderInner
for Layout<UnionSize, H, OkFv, OkUb, ErrFv, ErrUb, ErrSize, ErrAlign, ErrOffset>
Expand All @@ -108,7 +108,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
> IDeterminantProviderInner
for Layout<UnionSize, T<Budget>, OkFv, OkUb, ErrFv, ErrUb, ErrSize, ErrAlign, ErrOffset>
Expand Down Expand Up @@ -145,7 +145,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
Offset: Unsigned,
V: Unsigned,
Expand Down Expand Up @@ -179,7 +179,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
Offset: Unsigned,
V: Unsigned,
Expand Down Expand Up @@ -211,7 +211,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
Offset: Unsigned,
V: NonZero,
Expand Down Expand Up @@ -242,7 +242,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
> IDeterminantProviderInner
for DeterminantProvider<
Expand Down Expand Up @@ -271,7 +271,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
> IDeterminantProviderInner
for (
Expand All @@ -291,7 +291,7 @@ impl<
ErrFv: IForbiddenValues,
ErrUb: IBitMask,
ErrSize: Unsigned,
ErrAlign: PowerOf2,
ErrAlign: Alignment,
ErrOffset: Unsigned,
> IDeterminantProviderInner
for (
Expand Down
19 changes: 16 additions & 3 deletions stabby-abi/src/fatptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
/// This implies that this downcast will always yield `None` when attempting to downcast
/// values constructed accross an FFI.
///
/// Note that the compiler may chose to have multiple copies of the vtable, notably in optimized builds.
/// This means that even within a same compile unit, this function may fail to downcast a value even if
/// the type should have matched.
///
/// In general, you should prefer [`Self::stable_downcast_ref`]
///
/// # Safety
/// This may have false positives if all of the following applies:
/// - `self` was built from `&U`, within the same FFI-boundary,
Expand All @@ -280,20 +286,27 @@ impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
where
Vt: PartialEq + Copy + IConstConstructor<'a, T>,
{
eprintln!("{:p} vs {:p}", self.vtable(), Vt::VTABLE);
(self.vtable == Vt::VTABLE).then(|| unsafe { self.ptr.as_ref() })
}
/// Downcasts the reference based on its reflection report.
pub fn stable_downcast_ref<T: crate::IStable, Path>(&self) -> Option<&T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny, Path> + IConstConstructor<'a, T>,
{
(self.report() == T::REPORT).then(|| unsafe { self.ptr.as_ref() })
(self.id() == T::ID && self.report() == T::REPORT).then(|| unsafe { self.ptr.as_ref() })
}
/// Downcasts the mutable reference based on vtable equality.
///
/// This implies that this downcast will always yield `None` when attempting to downcast
/// values constructed accross an FFI.
///
/// Note that the compiler may chose to have multiple copies of the vtable, notably in optimized builds.
/// This means that even within a same compile unit, this function may fail to downcast a value even if
/// the type should have matched.
///
/// In general, you should prefer [`Self::stable_downcast_mut`]
///
/// # Safety
/// This may have false positives if all of the following applies:
/// - `self` was built from `&U`, within the same FFI-boundary,
Expand All @@ -310,13 +323,13 @@ impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
{
(self.vtable == Vt::VTABLE).then(|| unsafe { self.ptr.as_mut() })
}
/// Downcasts the reference based on its reflection report.
/// Downcasts the mutable reference based on its reflection report.
pub fn stable_downcast_mut<T: crate::IStable, Path>(&mut self) -> Option<&mut T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny, Path> + IConstConstructor<'a, T>,
P: IPtrMut,
{
(self.report() == T::REPORT).then(|| unsafe { self.ptr.as_mut() })
(self.id() == T::ID && self.report() == T::REPORT).then(|| unsafe { self.ptr.as_mut() })
}
}

Expand Down
8 changes: 4 additions & 4 deletions stabby-abi/src/istable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use crate::report::TypeReport;

use self::unsigned::IUnsignedBase;
use self::unsigned::{Alignment, IUnsignedBase};

use super::typenum2::*;
use super::unsigned::{IBitBase, NonZero};
Expand Down Expand Up @@ -42,7 +42,7 @@ pub unsafe trait IStable: Sized {
/// The size of the annotated type in bytes.
type Size: Unsigned;
/// The alignment of the annotated type in bytes.
type Align: PowerOf2;
type Align: Alignment;
/// The values that the annotated type cannot occupy.
type ForbiddenValues: IForbiddenValues;
/// The padding bits in the annotated types
Expand Down Expand Up @@ -344,7 +344,7 @@ unsafe impl<A: IStable, B: IStable> IStable for FieldPair<A, B> {
type UnusedBits =
<A::UnusedBits as IBitMask>::BitOr<<AlignedAfter<B, A::Size> as IStable>::UnusedBits>;
type Size = <AlignedAfter<B, A::Size> as IStable>::Size;
type Align = <A::Align as PowerOf2>::Max<B::Align>;
type Align = <A::Align as Alignment>::Max<B::Align>;
type HasExactlyOneNiche = <A::HasExactlyOneNiche as ISaturatingAdd>::SaturatingAdd<
<AlignedAfter<B, A::Size> as IStable>::HasExactlyOneNiche,
>;
Expand Down Expand Up @@ -482,7 +482,7 @@ unsafe impl<A: IStable, B: IStable> IStable for (Union<A, B>, B1) {
type ForbiddenValues = End;
type UnusedBits = End;
type Size = <A::Size as Unsigned>::Max<B::Size>;
type Align = <A::Align as PowerOf2>::Max<B::Align>;
type Align = <A::Align as Alignment>::Max<B::Align>;
type HasExactlyOneNiche = B0;
type ContainsIndirections = <A::ContainsIndirections as Bit>::Or<B::ContainsIndirections>;
primitive_report!("Union");
Expand Down
5 changes: 3 additions & 2 deletions stabby-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod alloc;
pub mod num;

pub use stabby_macros::{canary_suffixes, dynptr, export, import, stabby, vtable as vtmacro};
use typenum2::unsigned::Alignment;

use core::fmt::{Debug, Display};

Expand Down Expand Up @@ -256,7 +257,7 @@ unsafe impl<T, As: IStable> IStable for StableLike<T, As> {
/// transitively containing the emulated type are indeed ABI-stable.
pub struct NoNiches<
Size: Unsigned,
Align: PowerOf2,
Align: Alignment,
HasExactlyOneNiche: ISaturatingAdd = Saturator,
ContainsIndirections: Bit = B0,
>(
Expand All @@ -265,7 +266,7 @@ pub struct NoNiches<
);
unsafe impl<
Size: Unsigned,
Align: PowerOf2,
Align: Alignment,
HasExactlyOneNiche: ISaturatingAdd,
ContainsIndirections: Bit,
> IStable for NoNiches<Size, Align, HasExactlyOneNiche, ContainsIndirections>
Expand Down
Loading

0 comments on commit e14810c

Please sign in to comment.