From 0adae3578bcd46bf39c0baba63fb44c8d15e0431 Mon Sep 17 00:00:00 2001 From: Pierre Avital Date: Sun, 23 Jun 2024 20:38:50 +0200 Subject: [PATCH] Add validity check, which is used by safer_ffi --- stabby-abi/build.rs | 63 ++++++--- stabby-abi/src/istable.rs | 46 ++++++- stabby-abi/src/lib.rs | 4 + stabby-abi/src/stable_impls/mod.rs | 203 +--------------------------- stabby-abi/src/typenum2/unsigned.rs | 4 + 5 files changed, 103 insertions(+), 217 deletions(-) diff --git a/stabby-abi/build.rs b/stabby-abi/build.rs index 07ef29d..b100119 100644 --- a/stabby-abi/build.rs +++ b/stabby-abi/build.rs @@ -12,6 +12,13 @@ // Pierre Avital, // +use std::{ + fmt::Write as FmtWrite, + fs::File, + io::{BufWriter, Write}, + path::PathBuf, +}; + fn u(mut i: u128) -> String { let mut result = "UTerm".into(); let mut ids = Vec::new(); @@ -26,35 +33,59 @@ fn u(mut i: u128) -> String { result } -fn main() { - use std::{ - fs::File, - io::{BufWriter, Write}, - path::PathBuf, - }; +fn typenum_unsigned() -> std::io::Result<()> { const SEQ_MAX: u128 = 1000; - let padding_rs = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("unsigned.rs"); - let mut padding_file = BufWriter::new(File::create(padding_rs).unwrap()); + let filename = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("unsigned.rs"); + let mut file = BufWriter::new(File::create(filename).unwrap()); for i in 0..=SEQ_MAX { let u = u(i); - writeln!(padding_file, "/// {i}\npub type U{i} = {u};").unwrap(); - writeln!(padding_file, "/// {i}\npub type Ux{i:X} = {u};").unwrap(); - writeln!(padding_file, "/// {i}\npub type Ub{i:b} = {u};").unwrap(); + writeln!(file, "/// {i}\npub type U{i} = {u};")?; + writeln!(file, "/// {i}\npub type Ux{i:X} = {u};")?; + writeln!(file, "/// {i}\npub type Ub{i:b} = {u};")?; } for i in 0..39 { let ipow = 10u128.pow(i); let u = u(ipow); - writeln!(padding_file, "/// {i}\npub type U10pow{i} = {u};").unwrap(); + writeln!(file, "/// {i}\npub type U10pow{i} = {u};")?; if ipow > SEQ_MAX { - writeln!(padding_file, "/// {i}\npub type U{ipow} = {u};").unwrap(); - writeln!(padding_file, "/// {i}\npub type Ux{ipow:X} = {u};").unwrap(); - writeln!(padding_file, "/// {i}\npub type Ub{ipow:b} = {u};").unwrap(); + writeln!(file, "/// {i}\npub type U{ipow} = {u};")?; + writeln!(file, "/// {i}\npub type Ux{ipow:X} = {u};")?; + writeln!(file, "/// {i}\npub type Ub{ipow:b} = {u};")?; } } for i in 0..128 { let u = u(1 << i); - writeln!(padding_file, "/// {i}\npub type U2pow{i} = {u};").unwrap(); + writeln!(file, "/// {i}\npub type U2pow{i} = {u};")?; } + Ok(()) +} + +fn tuples() -> std::io::Result<()> { + let filename = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("tuples.rs"); + let mut file = BufWriter::new(File::create(filename).unwrap()); + for i in 0..128 { + writeln!( + file, + r##"/// An ABI stable tuple +#[crate::stabby] +pub struct Tuple{i}<{generics}>({fields}); +"##, + generics = (0..i).fold(String::new(), |mut acc, it| { + write!(acc, "T{it}, ").unwrap(); + acc + }), + fields = (0..i).fold(String::new(), |mut acc, it| { + write!(acc, "pub T{it}, ").unwrap(); + acc + }), + )?; + } + Ok(()) +} + +fn main() { + typenum_unsigned().unwrap(); + tuples().unwrap(); if let Ok(toolchain) = std::env::var("RUSTUP_TOOLCHAIN") { if toolchain.starts_with("nightly") { println!("cargo:rustc-cfg=stabby_nightly"); diff --git a/stabby-abi/src/istable.rs b/stabby-abi/src/istable.rs index b65ac9b..876b110 100644 --- a/stabby-abi/src/istable.rs +++ b/stabby-abi/src/istable.rs @@ -69,6 +69,17 @@ pub unsafe trait IStable: Sized { fn align() -> usize { Self::Align::USIZE } + /// Returns `true` if `ptr` points to memory that cannot be a valid value of `Self`. + /// + /// Note that this function returning `false` is not a guarantee that the value is valid, + /// as no heuristic can guarantee that. Notably, this heuristic will generally not look + /// through indirections. + /// + /// # Safety + /// Calling this may result in UB if `ptr` points to uninitialized memory at offsets where a forbidden value in `Self` exists. + unsafe fn is_invalid(ptr: *const u8) -> bool { + Self::ForbiddenValues::is_invalid(ptr) + } } /// A static proof that a type is "Plain Old Data". @@ -270,6 +281,11 @@ pub trait IForbiddenValues { type SelectFrom: ISingleForbiddenValue; /// Extract the first available forbidden value. type SelectOne: ISingleForbiddenValue; + /// Returns `true` if `ptr` points to a forbidden value. + /// + /// # Safety + /// Calling this on uninitialized memory is UB. + unsafe fn is_invalid(ptr: *const u8) -> bool; } /// A single multi-byte forbidden value. pub trait ISingleForbiddenValue { @@ -287,6 +303,9 @@ impl IForbiddenValues for End { type Or = T; type SelectFrom = End; type SelectOne = End; + unsafe fn is_invalid(_: *const u8) -> bool { + false + } } impl ISingleForbiddenValue for Saturator { type Push = Saturator; @@ -308,7 +327,9 @@ impl ISingleForbiddenValue type And = V; type Resolve = Self; } -impl IForbiddenValues for Array { +impl IForbiddenValues + for Array +{ type Shift = Array, T, Rest::Shift>; type Or = Or; type SelectFrom = @@ -316,6 +337,9 @@ impl IForbiddenValues for Array as ISingleForbiddenValue>::Push, >; type SelectOne = Array; + unsafe fn is_invalid(ptr: *const u8) -> bool { + ptr.add(Offset::USIZE).read() == T::U8 && Rest::is_invalid(ptr) + } } impl IForbiddenValues for Or { type Shift = Or, B::Shift>; @@ -323,6 +347,26 @@ impl IForbiddenValues for Or { type SelectFrom = as ISingleForbiddenValue>::Or>; type SelectOne = A::SelectOne; + unsafe fn is_invalid(ptr: *const u8) -> bool { + A::is_invalid(ptr) || B::is_invalid(ptr) + } +} +/// An inclusive range of forbidden values for a single byte. +pub struct ForbiddenRange = B1>, Offset: Unsigned>( + core::marker::PhantomData<(Min, Max, Offset)>, +); +impl = B1>, Offset: Unsigned> IForbiddenValues + for ForbiddenRange +{ + type Shift = ForbiddenRange>; + type Or = Or; + type SelectFrom = + as IBitBase>::_SfvTernary; + type SelectOne = Array; + unsafe fn is_invalid(ptr: *const u8) -> bool { + let v = ptr.add(Offset::USIZE).read(); + Min::U8 <= v && v <= Max::U8 + } } /// The union of 2 sets. pub struct Or(core::marker::PhantomData<(A, B)>); diff --git a/stabby-abi/src/lib.rs b/stabby-abi/src/lib.rs index 198d174..82663d0 100644 --- a/stabby-abi/src/lib.rs +++ b/stabby-abi/src/lib.rs @@ -390,6 +390,10 @@ pub mod report; pub mod slice; /// ABI-stable strs. pub mod str; +/// ABI-stable tuples. +pub mod tuples { + include!(concat!(env!("OUT_DIR"), "/tuples.rs")); +} pub use istable::{Array, End, IStable}; diff --git a/stabby-abi/src/stable_impls/mod.rs b/stabby-abi/src/stable_impls/mod.rs index 4e694b4..7a24c0f 100644 --- a/stabby-abi/src/stable_impls/mod.rs +++ b/stabby-abi/src/stable_impls/mod.rs @@ -12,7 +12,7 @@ // Pierre Avital, // -use crate::{istable::Or, str::Str, *}; +use crate::{str::Str, *}; macro_rules! same_as { ($t: ty, $($name: tt)*) => { @@ -192,114 +192,10 @@ unsafe impl IStable for core::marker::PhantomPinned { type ContainsIndirections = B0; primitive_report!("core::marker::PhantomPinned"); } -macro_rules! illegal_values { - ([$($l: tt)*], [$($r: tt)*]) => { - Or - }; - ($t: ty, $($tt: tt)*) => { - Or, illegal_values!($($tt)*)> - }; - ($t: ty) => { - Array - }; -} unsafe impl IStable for bool { type Align = U1; type Size = U1; - type ForbiddenValues = illegal_values!( - [ - [ - [ - [ - [[[U2], [U3, U4]], [[U5, U6], [U7, U8]]], - [[[U9, U10], [U11, U12]], [[U13, U14], [U15, U16]]] - ], - [ - [[[U17, U18], [U19, U20]], [[U21, U22], [U23, U24]]], - [[[U25, U26], [U27, U28]], [[U29, U30], [U31, U32]]] - ] - ], - [ - [ - [[[U33, U34], [U35, U36]], [[U37, U38], [U39, U40]]], - [[[U41, U42], [U43, U44]], [[U45, U46], [U47, U48]]] - ], - [ - [[[U49, U50], [U51, U52]], [[U53, U54], [U55, U56]]], - [[[U57, U58], [U59, U60]], [[U61, U62], [U63, U64]]] - ] - ] - ], - [ - [ - [ - [[[U65, U66], [U67, U68]], [[U69, U70], [U71, U72]]], - [[[U73, U74], [U75, U76]], [[U77, U78], [U79, U80]]] - ], - [ - [[[U81, U82], [U83, U84]], [[U85, U86], [U87, U88]]], - [[[U89, U90], [U91, U92]], [[U93, U94], [U95, U96]]] - ] - ], - [ - [ - [[[U97, U98], [U99, U100]], [[U101, U102], [U103, U104]]], - [[[U105, U106], [U107, U108]], [[U109, U110], [U111, U112]]] - ], - [ - [[[U113, U114], [U115, U116]], [[U117, U118], [U119, U120]]], - [[[U121, U122], [U123, U124]], [[U125, U126], [U127, U128]]] - ] - ] - ] - ], - [ - [ - [ - [ - [[[U129], [U130, U131]], [[U132, U133], [U134, U135]]], - [[[U136, U137], [U138, U139]], [[U140, U141], [U142, U143]]] - ], - [ - [[[U144, U145], [U146, U147]], [[U148, U149], [U150, U151]]], - [[[U152, U153], [U154, U155]], [[U156, U157], [U158, U159]]] - ] - ], - [ - [ - [[[U160, U161], [U162, U163]], [[U164, U165], [U166, U167]]], - [[[U168, U169], [U170, U171]], [[U172, U173], [U174, U175]]] - ], - [ - [[[U176, U177], [U178, U179]], [[U180, U181], [U182, U183]]], - [[[U184, U185], [U186, U187]], [[U188, U189], [U190, U191]]] - ] - ] - ], - [ - [ - [ - [[[U192, U193], [U194, U195]], [[U196, U197], [U198, U199]]], - [[[U200, U201], [U202, U203]], [[U204, U205], [U206, U207]]] - ], - [ - [[[U208, U209], [U210, U211]], [[U212, U213], [U214, U215]]], - [[[U216, U217], [U218, U219]], [[U220, U221], [U222, U223]]] - ] - ], - [ - [ - [[[U224, U225], [U226, U227]], [[U228, U229], [U230, U231]]], - [[[U232, U233], [U234, U235]], [[U236, U237], [U238, U239]]] - ], - [ - [[[U240, U241], [U242, U243]], [[U244, U245], [U246, U247]]], - [[[U248, U249], [U250, U251]], [[U252, U253], [U254, U255]]] - ] - ] - ] - ] - ); + type ForbiddenValues = crate::istable::ForbiddenRange; type UnusedBits = End; type HasExactlyOneNiche = B0; type ContainsIndirections = B0; @@ -836,100 +732,7 @@ sliceimpl!( unsafe impl IStable for core::cmp::Ordering { type Align = U1; type Size = U1; - type ForbiddenValues = illegal_values!( - [ - [ - [ - [ - [[[U2], [U3, U4]], [[U5, U6], [U7, U8]]], - [[[U9, U10], [U11, U12]], [[U13, U14], [U15, U16]]] - ], - [ - [[[U17, U18], [U19, U20]], [[U21, U22], [U23, U24]]], - [[[U25, U26], [U27, U28]], [[U29, U30], [U31, U32]]] - ] - ], - [ - [ - [[[U33, U34], [U35, U36]], [[U37, U38], [U39, U40]]], - [[[U41, U42], [U43, U44]], [[U45, U46], [U47, U48]]] - ], - [ - [[[U49, U50], [U51, U52]], [[U53, U54], [U55, U56]]], - [[[U57, U58], [U59, U60]], [[U61, U62], [U63, U64]]] - ] - ] - ], - [ - [ - [ - [[[U65, U66], [U67, U68]], [[U69, U70], [U71, U72]]], - [[[U73, U74], [U75, U76]], [[U77, U78], [U79, U80]]] - ], - [ - [[[U81, U82], [U83, U84]], [[U85, U86], [U87, U88]]], - [[[U89, U90], [U91, U92]], [[U93, U94], [U95, U96]]] - ] - ], - [ - [ - [[[U97, U98], [U99, U100]], [[U101, U102], [U103, U104]]], - [[[U105, U106], [U107, U108]], [[U109, U110], [U111, U112]]] - ], - [ - [[[U113, U114], [U115, U116]], [[U117, U118], [U119, U120]]], - [[[U121, U122], [U123, U124]], [[U125, U126], [U127, U128]]] - ] - ] - ] - ], - [ - [ - [ - [ - [[[U129], [U130, U131]], [[U132, U133], [U134, U135]]], - [[[U136, U137], [U138, U139]], [[U140, U141], [U142, U143]]] - ], - [ - [[[U144, U145], [U146, U147]], [[U148, U149], [U150, U151]]], - [[[U152, U153], [U154, U155]], [[U156, U157], [U158, U159]]] - ] - ], - [ - [ - [[[U160, U161], [U162, U163]], [[U164, U165], [U166, U167]]], - [[[U168, U169], [U170, U171]], [[U172, U173], [U174, U175]]] - ], - [ - [[[U176, U177], [U178, U179]], [[U180, U181], [U182, U183]]], - [[[U184, U185], [U186, U187]], [[U188, U189], [U190, U191]]] - ] - ] - ], - [ - [ - [ - [[[U192, U193], [U194, U195]], [[U196, U197], [U198, U199]]], - [[[U200, U201], [U202, U203]], [[U204, U205], [U206, U207]]] - ], - [ - [[[U208, U209], [U210, U211]], [[U212, U213], [U214, U215]]], - [[[U216, U217], [U218, U219]], [[U220, U221], [U222, U223]]] - ] - ], - [ - [ - [[[U224, U225], [U226, U227]], [[U228, U229], [U230, U231]]], - [[[U232, U233], [U234, U235]], [[U236, U237], [U238, U239]]] - ], - [ - [[[U240, U241], [U242, U243]], [[U244, U245], [U246, U247]]], - [[[U248, U249], [U250, U251]], [[U252, U253], [U254]]] - ] - ] - ] - ] - ); + type ForbiddenValues = crate::istable::ForbiddenRange; type UnusedBits = End; type HasExactlyOneNiche = B0; type ContainsIndirections = B0; diff --git a/stabby-abi/src/typenum2/unsigned.rs b/stabby-abi/src/typenum2/unsigned.rs index afcc6dd..96c4e27 100644 --- a/stabby-abi/src/typenum2/unsigned.rs +++ b/stabby-abi/src/typenum2/unsigned.rs @@ -72,6 +72,8 @@ pub trait IBitBase { /// Support for [`IBit`] type _FvTernary: IForbiddenValues; /// Support for [`IBit`] + type _SfvTernary: ISingleForbiddenValue; + /// Support for [`IBit`] type _UbTernary: IBitMask; /// Support for [`IBit`] type _SaddTernary: ISaturatingAdd; @@ -97,6 +99,7 @@ impl IBitBase for B0 { type _BmTernary = B; type _PTernary = B; type _FvTernary = B; + type _SfvTernary = B; type _UbTernary = B; type _SaddTernary = B; type _StabTernary = B; @@ -118,6 +121,7 @@ impl IBitBase for B1 { type _BmTernary = A; type _PTernary = A; type _FvTernary = A; + type _SfvTernary = A; type _UbTernary = A; type _SaddTernary = A; type _StabTernary = A;