Skip to content

Commit

Permalink
1. Large-scale update of the library, the ability to perform custom t…
Browse files Browse the repository at this point in the history
…rigger functions, adding a variety of trigger functions.

2. Documentation improvement
3. API State Handling
4. Adding more tests
5. Possibility to use both secure API version and non-secure API version at the same time.
6. Build Flags Extension
7. Adding a separate trigger that determines how many times the API does not work correctly, but retains undefined behavior.

*_--
  • Loading branch information
denisandroid committed Feb 2, 2022
1 parent 4adf3e2 commit 232682a
Show file tree
Hide file tree
Showing 15 changed files with 1,265 additions and 511 deletions.
24 changes: 20 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
[package]
name = "SafeManuallyDrop"
version = "0.1.2"
authors = ["Денис Котляров <[email protected]>"]
edition = "2018"
version = "0.1.5"
authors = ["Denis Kotlyarov <[email protected]>"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = [
"always_check_in_case_debug_assertions",
"enable_deprecated_hook",

"support_panic_trig",
"support_hook_trig" #,
#"support_count_trig"
]
always_check_in_case_debug_assertions = []
always_safe_manuallydrop = []

support_hook_trig = []
support_count_trig = []
support_panic_trig = []

enable_deprecated_hook = []

[dependencies]
6 changes: 4 additions & 2 deletions examples/combo_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ use SafeManuallyDrop::ManuallyDrop;
use std::ops::Deref;

fn main() {
assert_eq!(SafeManuallyDrop::core::flags::IS_SAFE_MODE, true);

let data = vec![1, 2, 3, 4];
let mut control_drop = ManuallyDrop::new(data);

let _e = control_drop.deref();
{
unsafe {
assert_eq!(control_drop.is_maybe_next_panic(), false);
assert_eq!(control_drop.is_next_trig(), false);
ManuallyDrop::drop(&mut control_drop);

assert_eq!(control_drop.is_maybe_next_panic(), true);
assert_eq!(control_drop.is_next_trig(), true);
// <<-- PANIC
ManuallyDrop::drop(&mut control_drop);
}
Expand Down
99 changes: 99 additions & 0 deletions src/beh/safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

use core::hash::Hash;
use crate::UnsafeStdManuallyDrop;
use crate::core::trig::TrigManuallyDrop;
use core::marker::PhantomData;

/// A safe version of the insecure manual control of freeing memory.
// #[repr(transparent)]
//#[derive(/*Copy,*/ Clone, Debug)]
#[derive(/*Copy,*/ Clone, Debug/*, Default, PartialEq, Eq, PartialOrd, Ord, Hash*/)]
pub struct SafeManuallyDrop<T, Trig> where T: ?Sized, Trig: TrigManuallyDrop {
pub (crate) state: StateManuallyDrop,
pub (crate) _pp: PhantomData<Trig>,
pub (crate) value: UnsafeStdManuallyDrop<T>,
}

crate::__codegen! {
@use;
#SafeManuallyDrop [is_safe: true];
}

//impl<T> Copy for ManuallyDrop<T> where T: ?Sized + Copy {} TODO

impl<T, Trig> Default for SafeManuallyDrop<T, Trig> where T: ?Sized + Default, Trig: TrigManuallyDrop {
#[inline(always)]
fn default() -> Self {
Self::new(
Default::default()
)
}
}

impl<T, Trig, Rhs> PartialEq<Rhs> for SafeManuallyDrop<T, Trig> where T: ?Sized + PartialEq<Rhs>, Trig: TrigManuallyDrop {
#[inline]
fn eq(&self, a: &Rhs) -> bool {
let value: &T = self.value.deref();
PartialEq::<Rhs>::eq(value, a)
}

#[inline]
fn ne(&self, a: &Rhs) -> bool {
let value: &T = self.value.deref();
PartialEq::<Rhs>::ne(value, a)
}
}

impl<T, Trig> Eq for SafeManuallyDrop<T, Trig> where T: Eq + PartialEq<SafeManuallyDrop<T, Trig>>, Trig: TrigManuallyDrop {
#[inline]
fn assert_receiver_is_total_eq(&self) {
let value: &T = self.value.deref();
Eq::assert_receiver_is_total_eq(value)
}
}

impl<T, Trig> Ord for SafeManuallyDrop<T, Trig> where T: Ord + PartialOrd<SafeManuallyDrop<T, Trig>>, Trig: TrigManuallyDrop {
#[inline]
fn cmp(&self, a: &Self) -> core::cmp::Ordering {
let value: &T = self.value.deref();
Ord::cmp(value, a)
}
}

impl<T, Trig, Rhs> PartialOrd<Rhs> for SafeManuallyDrop<T, Trig> where T: ?Sized + PartialOrd<Rhs>, Trig: TrigManuallyDrop {
#[inline]
fn partial_cmp(&self, a: &Rhs) -> Option<core::cmp::Ordering> {
let value: &T = self.value.deref();
PartialOrd::partial_cmp(value, a)
}
}

impl<T, Trig> Hash for SafeManuallyDrop<T, Trig> where T: ?Sized + Hash, Trig: TrigManuallyDrop {
#[inline]
fn hash<H>(&self, a: &mut H) where H: core::hash::Hasher {
let value: &T = self.value.deref();
Hash::hash(value, a)
}
}

impl<T, Trig> Drop for SafeManuallyDrop<T, Trig> where T: ?Sized, Trig: TrigManuallyDrop {
#[inline]
fn drop(&mut self) {
let ref mut value = self.value;
let ref state = self.state;

/*enum __HideTrig {}
impl TrigManuallyDrop for __HideTrig {
fn trig_next_invalid_beh<'a>(a: core::fmt::Arguments<'a>) -> ! {
Trig::trig_next_invalid_beh(a)
}
}*/

state.if_empty_then_run_trigfn::<Trig, _>(
|| unsafe {
// What for? - >> to ignore miri errors allocate.
UnsafeStdManuallyDrop::drop(value);
}
);
}
}
17 changes: 17 additions & 0 deletions src/beh/unsafe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

use core::marker::PhantomData;
use crate::UnsafeStdManuallyDrop;
use crate::core::trig::TrigManuallyDrop;

/// Insecure standard implementation of manual memory management.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnsafeManuallyDrop<T, Trig> where T: ?Sized, Trig: TrigManuallyDrop {
_pp: PhantomData<Trig>,
value: UnsafeStdManuallyDrop<T>,
}

crate::__codegen! {
@use;
#UnsafeManuallyDrop [is_safe: false];
}
143 changes: 143 additions & 0 deletions src/core/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@

#[macro_export]
#[doc(hidden)]
macro_rules! cfg_if_safemode {
[ #if_safe() { $($all:tt)* } $( else $($else_all:tt)* )? /*$($macros_data:tt)**/ ] => {
{
#[cfg(
any(
feature = "always_safe_manuallydrop",
all(feature = "always_check_in_case_debug_assertions", debug_assertions),
)
)] {
$($all)*
}

$(
#[cfg(not(
any(
feature = "always_safe_manuallydrop",
all(feature = "always_check_in_case_debug_assertions", debug_assertions),
)
))] {
$($else_all)*
}
)?
}

/*$crate::cfg_if_safemode! {
$($macros_data)*
}*/
};

[
$(#[$($meta:tt)*])*
#if_safe ( $($all:tt)* ) $($macros_data:tt)*
] => {
#[cfg(
any(
feature = "always_safe_manuallydrop",
all(feature = "always_check_in_case_debug_assertions", debug_assertions),
)
)]
$(#[$($meta)*])*
$($all)*

$crate::cfg_if_safemode! {
$($macros_data)*
}
};

[
$(#[$($meta:tt)*])*
#if_not_safe ( $($all:tt)* ) $($macros_data:tt)*
] => {
#[cfg(
not(
any(
feature = "always_safe_manuallydrop",
all(feature = "always_check_in_case_debug_assertions", debug_assertions),
)
)
)]
$(#[$($meta)*])*
$($all)*

$crate::cfg_if_safemode! {
$($macros_data)*
}
};

[] => {};
[ #if_safe { $($all:tt)* } ] => {
{
#[cfg(
any(
feature = "always_safe_manuallydrop",
all(feature = "always_check_in_case_debug_assertions", debug_assertions)
)
)] {
$($all)*
}
}
};
}

crate::cfg_if_safemode! {
#if_not_safe (pub const IS_SAFE_MODE: bool = false;)
#if_safe (pub const IS_SAFE_MODE: bool = true;)
}

#[cfg(feature = "support_panic_trig")]
pub const SUPPORT_PANIC_TRIG: bool = true;

#[cfg(not(feature = "support_panic_trig"))]
pub const SUPPORT_PANIC_TRIG: bool = false;

#[cfg(feature = "support_hook_trig")]
pub const SUPPORT_HOOK_TRIG: bool = true;

#[cfg(not(feature = "support_hook_trig"))]
pub const SUPPORT_HOOK_TRIG: bool = false;

#[cfg(feature = "support_count_trig")]
pub const SUPPORT_COUNT_TRIG: bool = true;

#[cfg(not(feature = "support_count_trig"))]
pub const SUPPORT_COUNT_TRIG: bool = false;

pub const SUPPORT_EMPTY_TRIG: bool = true;

#[cfg(test)]
#[test]
fn test_flag_is_safe_mode() {
#[allow(unused_assignments)]
let mut is_checked_c = 0;

#[cfg(feature = "always_safe_manuallydrop")] {
assert_eq!(IS_SAFE_MODE, true);

//#[allow(unused_assignments)] // error[E0658]: attributes on expressions are experimental
is_checked_c = 1;
}
if is_checked_c != 1 {} // fix error[E0658]: attributes on expressions are experimental

#[cfg( all(feature = "always_check_in_case_debug_assertions", debug_assertions) )] {
assert_eq!(IS_SAFE_MODE, true);

is_checked_c = 1;
}

#[cfg(not(
any(
all(feature = "always_check_in_case_debug_assertions", debug_assertions),
feature = "always_safe_manuallydrop"
)
))] {
assert_eq!(IS_SAFE_MODE, false);

is_checked_c = is_checked_c + 1;
}

assert_eq!(is_checked_c, 1);
}
6 changes: 3 additions & 3 deletions src/panic.rs → src/core/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ static mut HOOK: HookFunction = |args| {
};

// UNSAFE_MODE TODO!!
#[inline]
#[inline(always)]
pub unsafe fn set_hook(function: HookFunction) {
HOOK = function;
}

#[inline]
#[inline(always)]
pub fn take_hook() -> HookFunction {
// TODO UNSAFE MODE
unsafe { HOOK }
}

#[inline]
#[inline(always)]
pub fn run_hook(args: Arguments) -> ! {
(take_hook())(args)
}
Expand Down
Loading

0 comments on commit 232682a

Please sign in to comment.