{"id":21500256,"url":"https://github.com/clucompany/safemanuallydrop","last_synced_at":"2026-02-27T02:32:07.637Z","repository":{"id":57130256,"uuid":"376542310","full_name":"clucompany/SafeManuallyDrop","owner":"clucompany","description":"ManuallyDrop Safe: A robust version of ManuallyDrop with features and options for tracking undefined behavior.","archived":false,"fork":false,"pushed_at":"2024-07-06T16:36:28.000Z","size":152,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-24T07:38:40.201Z","etag":null,"topics":["clucompany","manuallydrop","no-std","safe-manually-drop","safemanuallydrop"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clucompany.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-13T12:47:14.000Z","updated_at":"2024-07-06T16:36:31.000Z","dependencies_parsed_at":"2024-11-23T17:36:04.158Z","dependency_job_id":null,"html_url":"https://github.com/clucompany/SafeManuallyDrop","commit_stats":{"total_commits":30,"total_committers":1,"mean_commits":30.0,"dds":0.0,"last_synced_commit":"01bfbb15751bd20e065aa46864100395b9567cff"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clucompany%2FSafeManuallyDrop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clucompany%2FSafeManuallyDrop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clucompany%2FSafeManuallyDrop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clucompany%2FSafeManuallyDrop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clucompany","download_url":"https://codeload.github.com/clucompany/SafeManuallyDrop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240236196,"owners_count":19769570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clucompany","manuallydrop","no-std","safe-manually-drop","safemanuallydrop"],"created_at":"2024-11-23T17:23:06.945Z","updated_at":"2026-02-27T02:32:07.583Z","avatar_url":"https://github.com/clucompany.png","language":"Rust","readme":"# SafeManuallyDrop\n[![CI](https://github.com/clucompany/SafeManuallyDrop/actions/workflows/CI.yml/badge.svg?event=push)](https://github.com/clucompany/SafeManuallyDrop/actions/workflows/CI.yml)\n[![Apache licensed](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE)\n[![crates.io](https://img.shields.io/crates/v/SafeManuallyDrop)](https://crates.io/crates/SafeManuallyDrop)\n[![Documentation](https://docs.rs/SafeManuallyDrop/badge.svg)](https://docs.rs/SafeManuallyDrop)\n\nA safe version of ManuallyDrop with various features and options to track undefined behavior when working with ManuallyDrop.\n\n# Use\n\n### 1. easy\n\n```rust,should_panic\nuse SafeManuallyDrop::ManuallyDrop;\nuse std::ops::Deref;\n\nfn main() {\n\t/*\n\t\tManuallyDrop - Depending on the build flag, a protected version of ManuallyDrop \n\t\tor an unprotected version of ManuallyDrop with a default trigger. \n\t*/\n\tif ManuallyDrop::is_safe_mode() {\n\t\t// ManuallyDrop is protected, let's do the standard behavior ManuallyDrop\n\t\t// but at the end we'll make the undefined behavior ManuallyDrop.\n\t\t\n\t\t// \n\t\tlet mut data = ManuallyDrop::new(vec![1, 2, 3, 4]);\n\t\tprintln!(\"data: {:?}\", data.deref());\n\t\t\n\t\t// to avoid warning if the always_compatible_stdapi flag is not used (can be removed)\n\t\t#[allow(unused_unsafe)]\n\t\tunsafe {\n\t\t\tassert_eq!(data.is_next_trig(), false); // VALID\n\t\t\tManuallyDrop::drop(\u0026mut data); // VALID\n\t\t\tassert_eq!(data.is_next_trig(), true); // VALID\n\t\t\t\n\t\t\t// \u003c\u003c-- PANIC\n\t\t\t/*\n\t\t\t\tthread 'main' panicked at 'Undefined behavior when using \n\t\t\t\tManuallyDrop(combo_replace_manudropstate), instead of the expected default \n\t\t\t\tstate, the current state: DropModeTrig.', src/core/trig/hook.rs:14:5\n\t\t\t*/\n\t\t\tManuallyDrop::drop(\u0026mut data); // INVALID, COMBO DROP\n\t\t}\n\t}else {\n\t\tprintln!(\"#[0] ManuallyDrop is an alias for AutoSafeManuallyDrop, \");\n\t\tprintln!(\"#[1] ManuallyDrop in the release build has no protection by default,\");\n\t\tprintln!(\"#[2] if ManuallyDrop is not protected it will be the same as in std.\");\n\t\tprintln!(\"#[3] To run the protected version, use `cargo run --example easy` or \");\n\t\tprintln!(\"`CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS=\\\"true\\\" cargo run --example easy --release`\");\n\t\tprintln!();\n\t\tprintln!(\"Or use concrete types instead of auto (AutoSafeManuallyDrop, AutoSafePanicManuallyDrop, AutoSafeHookManuallyDrop, AutoSafeCounterManuallyDrop, AlwaysSafeManuallyDrop, AlwaysSafePanicManuallyDrop, AlwaysSafeHookManuallyDrop, AlwaysSafeCounterManuallyDrop) specific data types with specific behavior.\");\n\t}\n}\n```\n\n### 2. EasyStruct\n\n```rust\n// 1. In production code, it is recommended to use AutoSafe instead of AlwaysSafe, \n// this will eliminate unnecessary checks in the release build, but leave \n// them in the test build.\n//\n// 2. It is generally recommended to use Panic or Abort as a trigger for undefined behavior.\n//\nuse SafeManuallyDrop::AlwaysSafePanicManuallyDrop as ManuallyDrop;\n\n#[derive(Default, Debug)]\nstruct ControlDrop(usize);\n\n// Properly created and validated MyLogicData structure.\n#[derive(Default)]\nstruct MyLogicData {\n\tdata: ManuallyDrop\u003cControlDrop\u003e\n}\n\nimpl MyLogicData {\n\t/// Exceptional logic. As a result, the original value will always be returned.\n\tpub fn ignore_mylogic_and_getdata(mut self) -\u003e ControlDrop {\n\t\t// Note that you can only `take` once, any further operation with \n\t\t// ManuallyDrop will cause a panic.\n\t\tlet data = unsafe {\n\t\t\tManuallyDrop::take(\u0026mut self.data)\n\t\t};\n\t\t\n\t\t// ManuallyDrop::forget analog forget(self).\n\t\tManuallyDrop::forget(self);\n\t\t\n\t\t/*\n\t\t\tdata logic\n\t\t*/\n\t\t\n\t\tdata\n\t}\n}\n\nimpl Drop for MyLogicData {\n\tfn drop(\u0026mut self) {\n\t\t/*\n\t\t\tdef logic\n\t\t*/\n\t\tprintln!(\"MyLogicData, indata: {:?}\", self.data);\n\t\t\n\t\t/*\n\t\t\tNotification\n\t\t\t1. `ManuallyDrop` always requires it to be freed when it is no longer needed.\n\t\t\t2. Once `ManuallyDrop` is freed, you will not be able to read data from it\n\t\t\t3. You cannot drop `ManuallyDrop` twice.\n\t\t\t...\n\t\t\t\n\t\t\tYou can remove the `unsafe` flags if you don't use the `always_compatible_stdapi` flag.\n\t\t*/\n\t\tunsafe {\n\t\t\tManuallyDrop::drop(\u0026mut self.data);\n\t\t}\n\t}\n}\n\nfn main() {\n\t{\n\t\t// run my logic\n\t\tlet indata = MyLogicData::default();\n\t\tdrop(indata);\n\t\t\n\t\t// This case will just make the logic default by executing the code in drop.\n\t}\n\t{\n\t\t// ignore_mylogic\n\t\tlet indata = MyLogicData::default();\n\t\tlet cd_data = indata.ignore_mylogic_and_getdata();\n\t\n\t\tprintln!(\"ignore_mylogic: {:?}\", cd_data);\n\t\t\n\t\t// In this case, the standard reset logic is eliminated and another \n\t\t// specific principle is used, which is embedded in the function with data return.\n\t}\n}\n```\n\n### 3. hook\n\n```rust\nuse std::ops::Deref;\n\n// For better performance, we recommend using AutoSafeHookManuallyDrop instead \n// of AlwaysSafeHookManuallyDrop. The AutoSafeHookManuallyDrop type depends on \n// the type of build, debug or release will be with the safe or insecure version\n// of ManuallyDrop.\nuse SafeManuallyDrop::AlwaysSafeHookManuallyDrop as ManuallyDrop;\n\nfn main() {\n\tunsafe {\n\t\tManuallyDrop::set_hook(|args| {\n\t\t\tprintln!(\"!!!{:?}\", args);\n\t\t\t\n\t\t\tfor _ in 0..3 {\n\t\t\t\tstd::thread::sleep(std::time::Duration::from_millis(1000));\n\t\t\t}\n\t\t\t\n\t\t\tprintln!(\"exit\");\n\t\t\tstd::process::exit(0x0100);\n\t\t});\n\t}\n\t\n\tlet mut data = ManuallyDrop::new(vec![1, 2, 3, 4]);\n\tprintln!(\"data: {:?}\", data.deref());\n\t\n\t// to avoid warning if the always_compatible_stdapi flag is not used (can be removed)\n\t#[allow(unused_unsafe)]\n\tunsafe {\n\t\tassert_eq!(data.is_next_trig(), false); // VALID\n\t\tManuallyDrop::drop(\u0026mut data); // VALID\n\t\tassert_eq!(data.is_next_trig(), true); // VALID\n\t\t\n\t\t// \u003c\u003c-- HOOK\n\t\tManuallyDrop::drop(\u0026mut data); // INVALID, COMBO DROP\n\t}\n}\n```\n\n### 4. counter\n\n```rust\n// Let me remind you that CounterManuallyDrop by behavior allows undefined \n// behavior in the same way as ManuallyDrop, but, unlike ManuallyDrop, \n// Counter keeps a counter of the number of undefined behavior triggers.\n\n// !!!!\n// CounterManuallyDrop is experimental and changes the behavior of \n// the trigger trait for all types.\n\n#[cfg(feature = \"support_count_trig\")]\nuse SafeManuallyDrop::AutoSafeCounterManuallyDrop as ManuallyDrop;\n\n#[cfg(not(feature = \"support_count_trig\"))]\nuse SafeManuallyDrop::ManuallyDrop;\n\nuse std::ops::Deref;\n\n#[allow(unreachable_code)]\nfn main() {\n\t#[cfg(not(feature = \"support_count_trig\"))] {\n\t\tprintln!(\"To run the example, a build with feature: support_count_trig is required,\");\n\t\tprintln!(\"exp: cargo run --example counter --all-features\");\n\t\tprintln!(\"end.\");\n\t\t\n\t\treturn;\n\t}\n\t\n\tlet mut data = ManuallyDrop::new(\u0026[1, 2, 3, 4]);\n\tprintln!(\"data: {:?}\", data.deref());\n\t\n\t#[allow(unused_unsafe)] // feature !always_compatible_stdapi\n\tunsafe {\n\t\tassert_eq!(data.is_next_trig(), false); // VALID, triggers never fired\n\t\t\n\t\t// =================\n\t\t// !!! ATTENTION !!!\n\t\t// =================\n\t\t// Procedure:\n\t\t// 1. Free up memory and try to read it\n\t\t// 2. Re-free memory\n\t\tManuallyDrop::drop(\u0026mut data); // VALID\n\t\tassert_eq!(data.is_next_trig(), true); // VALID, counter trigger worked.\n\t\t\n\t\tManuallyDrop::drop(\u0026mut data); // \u003c\u003c-- INVALID BEH, COUNTER += 1 (=1), COMBO DROP\n\t}\n\t\n\t// !!! Reading an already freed value\n\tprintln!(\"data: {:?}\", \u0026data); // \u003c\u003c-- INVALID BEH, COUNTER += 1 (=2)\n\t\n\t// to avoid warning if the always_compatible_stdapi flag is not used (can b removed)\n\t#[allow(unused_unsafe)] \n\tlet _data2 = unsafe { // \u003c\u003c-- INVALID BEH, COUNTER += 1 (=3)\n\t\t// !!! Trying to get the freed value\n\t\tManuallyDrop::take(\u0026mut data)\n\t};\n\t\n\t#[cfg(feature = \"support_count_trig\")]\n\tassert_eq!(ManuallyDrop::get_count_trig_events(), 3); // \u003c-- The number of times the undefined behavior was triggered.\n}\n```\n\n### 1. PlugAndPlay (Minimal, Panic)\n```rust,ignore\n[dependencies.SafeManuallyDrop]\nversion = \"1.0.3\"\ndefault-features = false\nfeatures = [\n\t\"always_check_in_case_debug_assertions\", \n\t\n\t#\"always_compatible_stdapi\",\n\t\n\t\"support_panic_trig\",\n\t\"always_deftrig_panic\"\n]\n```\n\n### 2. PlugAndPlay (Minimal, Abort)\n```rust,ignore\n[dependencies.SafeManuallyDrop]\nversion = \"1.0.3\"\ndefault-features = false\nfeatures = [\n\t\"always_check_in_case_debug_assertions\", \n\t\n\t#\"always_compatible_stdapi\",\n\t\n\t\"support_abort_trig\",\n\t\"always_deftrig_abort\"\n]\n```\n\n### 3. PlugAndPlay (Minimal, Hook)\n```rust,ignore\n[dependencies.SafeManuallyDrop]\nversion = \"1.0.3\"\ndefault-features = false\nfeatures = [\n\t\"always_check_in_case_debug_assertions\", \n\t\n\t#\"always_compatible_stdapi\",\n\t\n\t\"support_hookfn_trig\",\n\t\"always_deftrig_hookfn\"\n]\n```\n\n# cargo.toml -\u003e features\n\n```rust,ignore\n// Flags:\n//\n// ManuallyDrop and AutoManuallyDrop are always type safe and are automatically \n// checked on use if the debug_assertions flag is enabled (the flag is automatically \n// enabled if test build, debug build, or env: CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS=true).\n//\n// (Also, AlwaysSafeManuallyDrop is always checked for safety when it is used, regardless of the flags.)\n\"always_check_in_case_debug_assertions\", \n\n// ManuallyDrop and AutoManuallyDrop are always checked when used, \n// regardless of external flags.\n//\n// (Also, AlwaysSafeManuallyDrop is always checked for safety when it is used, regardless of the flags.)\n//\"always_safe_manuallydrop\",\n\n// Enable additional internal checks of the SafeManuallyDrop library when \n// the debug_assertions flag is enabled (does not depend on the always_check_in_case_debug_assertions \n// and always_safe_manuallydrop options). This flag type only applies to internal \n// library function checks, it is independent of ManuallyDrop and its valid or invalid usage.\n//\n// \"allow_extended_debug_assertions\",\n\n// Preserve unsafe fn flags even if functions are safe \n// (may be required for additional compatibility with the standard API)\n\"always_compatible_stdapi\",\n\n// Always create a modular table of library flags used in the build.\n// (crate::core::flags)\n\"flags_table\",\n\n// Trigs:\n//\n// Ability to determine if an empty loop trigger has been executed.\n\"support_istrig_loop\",\n\n// Support for PanicManuallyDrop, in case of undefined behavior \n// of ManuallyDrop there will be a panic.\n\"support_panic_trig\",\n\n// Support for AbortManuallyDrop, in case of undefined behavior \n// of ManuallyDrop there will be a abort. (Note that this feature requires std.)\n//\"support_abort_trig\",\n\n// HookManuallyDrop support, in case of undefined HookManuallyDrop behavior, \n// the hook function will be called.\n\"support_hookfn_trig\",\n\n// Support for CounterManuallyDrop, in case of undefined behavior, \n// CounterManuallyDrop will add +1 to the counter.\n//\"support_count_trig\",\n\n// The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always \n// cause a panic in case of undefined behavior.\n//\"always_deftrig_panic\",\n\n// The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always \n// cause a abort in case of undefined behavior.\n//\"always_deftrig_abort\",\n\n// The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always \n// call the hook function in case of undefined behavior.\n\"always_deftrig_hookfn\",\n\n// The behavior for the simple AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop type will always call \n// the +1 counter function in case of undefined behavior.\n//\"always_deftrig_count\",\n\n// The behavior for the simple type AutoSafeManuallyDrop/AlwaysSafeManuallyDrop/ManuallyDrop will always call \n// the eternal loop function in case of undefined behavior.\n//\"always_deftrig_loop\"\n```\n\n# License\n\nCopyright 2022 #UlinProject Denis Kotlyarov (Денис Котляров)\n\nLicensed under the Apache License, Version 2.0\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclucompany%2Fsafemanuallydrop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclucompany%2Fsafemanuallydrop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclucompany%2Fsafemanuallydrop/lists"}