Skip to content

Commit 4ee5256

Browse files
committed
1. Updated Github actions to fully test "features".
2. Library version updated to 1.0.3. 3. Added support for AbortManuallyDrop (requires support for std), in case of undefined behavior breaks the entire program with an error output. 4. Documentation update 5. Updated examples 6. Detector code for the default ManuallyDrop type has been updated.
1 parent df6740b commit 4ee5256

File tree

17 files changed

+405
-97
lines changed

17 files changed

+405
-97
lines changed

.github/workflows/CI.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,11 @@ jobs:
3434
run: cargo test --no-default-features --lib --verbose
3535
- name: Run cargo alltest
3636
run: cargo test --all-features --verbose
37-
37+
- name: PanicManDrop
38+
run: cargo test --no-default-features --features always_build_flagstable,allow_fullinternal_debug_assertions,always_check_in_case_debug_assertions,always_deftrig_panic,support_panic_trig --lib --verbose
39+
- name: AbortManDrop
40+
run: cargo test --no-default-features --features always_build_flagstable,allow_fullinternal_debug_assertions,always_check_in_case_debug_assertions,always_deftrig_abort,support_abort_trig --lib --verbose
41+
- name: HookFnManDrop
42+
run: cargo test --no-default-features --features always_build_flagstable,allow_fullinternal_debug_assertions,always_check_in_case_debug_assertions,always_deftrig_hookfn,support_hookfn_trig --lib --verbose
43+
- name: CountFnManDrop
44+
run: cargo test --no-default-features --features always_build_flagstable,allow_fullinternal_debug_assertions,always_check_in_case_debug_assertions,always_deftrig_count,support_count_trig --lib --verbose

Cargo.toml

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "SafeManuallyDrop"
3-
version = "1.0.2"
3+
version = "1.0.3"
44
authors = ["Denis Kotlyarov (Денис Котляров) <[email protected]>"]
55
repository = "https://github.com/clucompany/SafeManuallyDrop.git"
66
edition = "2021"
@@ -23,7 +23,6 @@ rustdoc-args = ["--cfg", "docsrs"]
2323
default = [
2424
# Flags:
2525
#
26-
2726
# ManuallyDrop and AutoManuallyDrop are always type safe and are automatically
2827
# checked on use if the debug_assertions flag is enabled (the flag is automatically
2928
# enabled if test build, debug build, or env: CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS=true).
@@ -54,13 +53,16 @@ default = [
5453

5554
# Trigs:
5655
#
57-
5856
# Ability to determine if an empty loop trigger has been executed.
5957
"support_istrig_loop",
6058

6159
# Support for PanicManuallyDrop, in case of undefined behavior
62-
# of PanicManuallyDrop there will be a panic.
63-
"support_panic_trig",
60+
# of ManuallyDrop there will be a panic.
61+
"support_panic_trig",
62+
63+
# Support for AbortManuallyDrop, in case of undefined behavior
64+
# of ManuallyDrop there will be a abort. (Note that this feature requires std.)
65+
#"support_abort_trig",
6466

6567
# HookManuallyDrop support, in case of undefined HookManuallyDrop behavior,
6668
# the hook function will be called.
@@ -74,9 +76,13 @@ default = [
7476
# cause a panic in case of undefined behavior.
7577
#"always_deftrig_panic",
7678

79+
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always
80+
# cause a abort in case of undefined behavior.
81+
#"always_deftrig_abort",
82+
7783
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always
7884
# call the hook function in case of undefined behavior.
79-
#"always_deftrig_hookfn",
85+
"always_deftrig_hookfn",
8086

8187
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always call
8288
# the +1 counter function in case of undefined behavior.
@@ -85,39 +91,61 @@ default = [
8591
# The behavior for the simple type AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop will always call
8692
# the eternal loop function in case of undefined behavior.
8793
#"always_deftrig_loop"
88-
89-
# INFO:
90-
# If the behavior for the general AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop is not fixed,
91-
# the behavior will be determined according to the following scheme:
92-
#
93-
# always_deftrig_panic not exists AND
94-
# always_deftrig_hookfn not exists AND
95-
# always_deftrig_count not exists AND
96-
# always_deftrig_loop not exists THEN
97-
#
98-
# support_hookfn_trig -> Hook, else:
99-
# support_panic_trig -> Panic, else:
100-
# support_count_trig -> Count, else:
101-
# Loop
102-
#
10394
]
95+
96+
# ManuallyDrop and AutoManuallyDrop are always type safe and are automatically
97+
# checked on use if the debug_assertions flag is enabled (the flag is automatically
98+
# enabled if test build, debug build, or env: CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS=true).
99+
#
100+
# (Also, AlwaysSafeManuallyDrop is always checked for safety when it is used, regardless of the flags.)
104101
always_check_in_case_debug_assertions = []
102+
# ManuallyDrop and AutoManuallyDrop are always checked when used,
103+
# regardless of external flags.
104+
#
105+
# (Also, AlwaysSafeManuallyDrop is always checked for safety when it is used, regardless of the flags.)
105106
always_safe_manuallydrop = []
106107

108+
# Enable additional internal checks of the SafeManuallyDrop library when
109+
# the debug_assertions flag is enabled (does not depend on the always_check_in_case_debug_assertions
110+
# and always_safe_manuallydrop options). This flag type only applies to internal
111+
# library function checks, it is independent of ManuallyDrop and its valid or invalid usage.
107112
allow_fullinternal_debug_assertions = []
108113

114+
# Always create a modular table of library flags used in the build.
115+
# (crate::core::flags)
109116
always_build_flagstable = []
110117

111118
support_hookfn_trig = []
119+
# Support for CounterManuallyDrop, in case of undefined behavior,
120+
# CounterManuallyDrop will add +1 to the counter.
112121
support_count_trig = []
122+
# Support for AbortManuallyDrop, in case of undefined behavior
123+
# of ManuallyDrop there will be a abort. (Note that this feature requires std.)
124+
support_abort_trig = []
125+
# Support for PanicManuallyDrop, in case of undefined behavior
126+
# of ManuallyDrop there will be a panic.
113127
support_panic_trig = []
128+
# Ability to determine if an empty loop trigger has been executed.
114129
support_istrig_loop = []
115130

131+
# Preserve unsafe fn flags even if functions are safe
132+
# (may be required for additional compatibility with the standard API)
116133
always_compatible_stdapi = []
117134

135+
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always
136+
# cause a panic in case of undefined behavior.
118137
always_deftrig_panic = []
138+
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always
139+
# cause a abort in case of undefined behavior.
140+
always_deftrig_abort = []
141+
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always
142+
# call the hook function in case of undefined behavior.
119143
always_deftrig_hookfn = []
144+
# The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always call
145+
# the +1 counter function in case of undefined behavior.
120146
always_deftrig_count = []
147+
# The behavior for the simple type AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop will always call
148+
# the eternal loop function in case of undefined behavior.
121149
always_deftrig_loop = []
122150

123151
[dependencies]

examples/abort.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
3+
// This example requires `support_abort_trig` support to work.
4+
5+
#[cfg(feature = "support_abort_trig")]
6+
use SafeManuallyDrop::AlwaysSafeAbortManuallyDrop as ManuallyDrop;
7+
8+
#[cfg(not(feature = "support_abort_trig"))]
9+
use SafeManuallyDrop::ManuallyDrop;
10+
11+
use std::ops::Deref;
12+
13+
#[allow(unreachable_code)]
14+
fn main() {
15+
#[cfg(not(feature = "support_abort_trig"))] {
16+
println!("To run the example, a build with feature: support_abort_trig is required,");
17+
println!("exp: cargo run --example abort --all-features");
18+
println!("end.");
19+
20+
return;
21+
}
22+
23+
let mut data = ManuallyDrop::new(vec![1, 2, 3, 4]);
24+
println!("data: {:?}", data.deref());
25+
26+
#[allow(unused_unsafe)] // to avoid warning if the always_compatible_stdapi flag is not used (can be removed)
27+
unsafe {
28+
assert_eq!(data.is_next_trig(), false); // VALID
29+
ManuallyDrop::drop(&mut data); // VALID
30+
assert_eq!(data.is_next_trig(), true); // VALID
31+
32+
// <<-- PANIC
33+
/*
34+
Undefined behavior when using ManuallyDrop(combo_replace_manudropstate),
35+
instead of the expected default state, the current state: DropModeTrig.
36+
37+
Emergency stop.
38+
*/
39+
ManuallyDrop::drop(&mut data); // INVALID, COMBO DROP
40+
}
41+
}

examples/easy_struct.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
2+
// 1. In production code, it is recommended to use AutoSafe instead of AlwaysSafe,
3+
// this will eliminate unnecessary checks in the release build, but leave
4+
// them in the test build.
5+
//
6+
// 2. It is generally recommended to use Panic or Abort as a trigger for undefined behavior.
7+
//
8+
use SafeManuallyDrop::AlwaysSafePanicManuallyDrop as ManuallyDrop;
9+
10+
#[derive(Default, Debug)]
11+
struct ControlDrop(usize);
12+
13+
// Properly created and validated MyLogicData structure.
14+
#[derive(Default)]
15+
struct MyLogicData {
16+
data: ManuallyDrop<ControlDrop>
17+
}
18+
19+
impl MyLogicData {
20+
/// Exceptional logic. As a result, the original value will always be returned.
21+
pub fn ignore_mylogic_and_getdata(mut self) -> ControlDrop {
22+
// Note that you can only `take` once, any further operation with
23+
// ManuallyDrop will cause a panic.
24+
let data = unsafe {
25+
ManuallyDrop::take(&mut self.data)
26+
};
27+
28+
// ManuallyDrop::forget analog forget(self).
29+
ManuallyDrop::forget(self);
30+
31+
/*
32+
data logic
33+
*/
34+
35+
data
36+
}
37+
}
38+
39+
impl Drop for MyLogicData {
40+
fn drop(&mut self) {
41+
/*
42+
def logic
43+
*/
44+
println!("MyLogicData, indata: {:?}", self.data);
45+
46+
/*
47+
Notification
48+
1. `ManuallyDrop` always requires it to be freed when it is no longer needed.
49+
2. Once `ManuallyDrop` is freed, you will not be able to read data from it
50+
3. You cannot drop `ManuallyDrop` twice.
51+
...
52+
53+
You can remove the `unsafe` flags if you don't use the `always_compatible_stdapi` flag.
54+
*/
55+
unsafe {
56+
ManuallyDrop::drop(&mut self.data);
57+
}
58+
}
59+
}
60+
61+
fn main() {
62+
{
63+
// run my logic
64+
let indata = MyLogicData::default();
65+
drop(indata);
66+
67+
// This case will just make the logic default by executing the code in drop.
68+
}
69+
{
70+
// ignore_mylogic
71+
let indata = MyLogicData::default();
72+
let cd_data = indata.ignore_mylogic_and_getdata();
73+
74+
println!("ignore_mylogic: {:?}", cd_data);
75+
76+
// In this case, the standard reset logic is eliminated and another
77+
// specific principle is used, which is embedded in the function with data return.
78+
}
79+
}

src/beh/auto.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11

2+
//! Depending on the build flag, a protected version of ManuallyDrop
3+
//! or an unprotected version of ManuallyDrop.
4+
25
/// An internal macro that replaces many built-in assembly safety checks for
36
/// the default ManuallyDrop type.
47
///

src/beh/safe.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
//! A safe version of the insecure manual control of freeing memory.
3+
24
use crate::UnsafeStdManuallyDrop;
35
use crate::core::trig::TrigManuallyDrop;
46
use core::marker::PhantomData;

src/beh/unsafe.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
//! Insecure standard implementation of manual memory management.
3+
24
use core::marker::PhantomData;
35
use crate::UnsafeStdManuallyDrop;
46
use crate::core::trig::TrigManuallyDrop;

src/core/flags.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
//! Flags used when building this library
3+
24
/// Whether a table of build flags to use was created
35
/// when the library was compiled.
46
pub const IS_BUILD_FLAGSTABLE: bool = true;
@@ -29,6 +31,17 @@ pub const IS_SUPPORT_HOOKFN_TRIG: bool = {
2931
}
3032
};
3133

34+
/// Whether the library build flag was used to support abort_trig.
35+
pub const IS_SUPPORT_ABORT_TRIG: bool = {
36+
#[cfg(feature = "support_abort_trig")] {
37+
true
38+
}
39+
40+
#[cfg(not(feature = "support_abort_trig"))] {
41+
false
42+
}
43+
};
44+
3245
/// Whether the library build flag was used to support count_trig.
3346
pub const IS_SUPPORT_COUNT_TRIG: bool = {
3447
#[cfg(feature = "support_count_trig")] {

src/core/state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
//! AtomicStates for ManuallyDrop
3+
24
#[cfg(all(test, feature = "support_panic_trig"))]
35
use crate::core::trig::panic::PanicTrigManuallyDrop;
46
use core::fmt::Display;

src/core/trig/abort.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
use core::fmt::Arguments;
3+
use crate::core::trig::TrigManuallyDrop;
4+
5+
/// A protected version of ManuallyDrop with a function to
6+
/// execute a abort in case of undefined behavior of the ManuallyDrop logic.
7+
pub type AlwaysSafeAbortManuallyDrop<T> = crate::beh::safe::SafeManuallyDrop<T, AbortTrigManuallyDrop>;
8+
9+
/// A secure or non-secure version of ManuallyDrop with a function to trigger
10+
/// a abort in case of undefined behavior of the ManuallyDrop logic.
11+
pub type AutoSafeAbortManuallyDrop<T> = crate::beh::auto::AutoSafeManuallyDrop<T, AbortTrigManuallyDrop>;
12+
13+
/// In case of undefined behavior of manual memory management,
14+
/// perform a normal abort.
15+
pub enum AbortTrigManuallyDrop {}
16+
17+
impl TrigManuallyDrop for AbortTrigManuallyDrop {
18+
#[inline(always)]
19+
fn trig_next_invalid_beh<'a>(a: Arguments<'a>) -> trig_manuallydrop_returntype!() {
20+
use std::io::Write;
21+
22+
{
23+
let mut lock = std::io::stderr().lock();
24+
let _e = write!(lock, "{}\n", a);
25+
let _e = lock.flush();
26+
}
27+
28+
std::process::abort();
29+
}
30+
}

0 commit comments

Comments
 (0)