diff --git a/Cargo.lock b/Cargo.lock index 6ce4a59..5e047b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "leak_memory" +version = "0.1.0" +dependencies = [ + "libc", +] + [[package]] name = "libc" version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "urine" -version = "0.1.0" -dependencies = [ - "libc", -] diff --git a/Cargo.toml b/Cargo.toml index f2be850..96f2fce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,13 @@ [package] -name = "urine" +name = "leak_memory" version = "0.1.0" +authors = ["Tyler Murphy "] edition = "2021" +description = "The enterprise way to leak memory" +license = "MIT++" +exclude = [".git", ".gitignore", "target"] +rust-version = "1.69" # hehe funny +readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..04226c0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +The Software shall be used for Evil, not Good. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b620d31 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ + +# Leak Memory + +leaks memory uwu + +## Examples + +Leak 1337 bytes of memory + +```rs +use leak_memory::{leak, LeakMethod}; + +fn main() { + leak(1337, LeakMethod::Lazy); +} +``` + +Leak 69 kibibytes + +```rs +use leak_memory::{leak, LeakMethod, LeakAmount}; + +fn main() { + leak("69kib".parse::().unwrap(), LeakMethod::Rust); +} +``` + + +## Compilation + +dont diff --git a/src/lib.rs b/src/lib.rs index 2b5e3ac..b9a7b07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,33 +1,35 @@ use std::cell::RefCell; use libc::malloc; -use std::fmt::{Result, Display, Formatter}; +use std::fmt::{self, Display, Formatter}; -pub mod parse; +mod parse; #[derive(Clone, Debug)] -pub enum PissError { +pub enum LeakError { + Unexpected(char), InvalidSuffix(String), InvalidNumber(String), NumberNotPositive } -impl Display for PissError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { +impl Display for LeakError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - Self::InvalidSuffix(s) => write!(f, "I cannot piss the suffix {s:?}"), - Self::InvalidNumber(s) => write!(f, "I cannot piss the invalid number {s:?}"), - Self::NumberNotPositive => write!(f, "I cannot piss nonexistent memory") + Self::Unexpected(c) => write!(f, "Unexpected character: '{c}'"), + Self::InvalidSuffix(s) => write!(f, "Invalid file size suffix: '{s}'"), + Self::InvalidNumber(s) => write!(f, "Invalid number: '{s}'"), + Self::NumberNotPositive => write!(f, "Cannot leak negative memory") } } } #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct PissAmount { - to_piss: u128 +pub struct LeakAmount { + to_leak: u128 } #[derive(Copy, Clone, Debug)] -pub enum Toliet { +pub enum LeakMethod { Rust, Lazy, Unsafe @@ -42,7 +44,7 @@ thread_local!(static TOLIET: RefCell>> = RefCell::new(Vec::new())); fn leak_lazy(amount: usize) { TOLIET.with(|t| { t.borrow_mut().push(Vec::::with_capacity(amount)); - }) + }); } fn leak_unsafe(amount: usize) { @@ -51,16 +53,21 @@ fn leak_unsafe(amount: usize) { } } -fn leak_match(amount: usize, method: Toliet) { +fn leak_match(amount: usize, method: LeakMethod) { match method { - Toliet::Rust => leak_rust(amount), - Toliet::Lazy => leak_lazy(amount), - Toliet::Unsafe => leak_unsafe(amount), + LeakMethod::Rust => leak_rust(amount), + LeakMethod::Lazy => leak_lazy(amount), + LeakMethod::Unsafe => leak_unsafe(amount), } } -pub fn leak>(amount: T, method: Toliet) { - let num: u128 = amount.into().to_piss; +pub fn leak>(amount: T, method: LeakMethod) -> Result<(), LeakError> { + let num: u128 = amount.into().to_leak; + + if num <= 0 { + return Err(LeakError::NumberNotPositive) + } + let count = num / usize::MAX as u128; for _ in 0..count { @@ -68,8 +75,10 @@ pub fn leak>(amount: T, method: Toliet) { } leak_match((num % usize::MAX as u128) as usize, method); + + Ok(()) } -pub async fn leak_async>(amount: T, method: Toliet) { - leak(amount, method); +pub async fn leak_async + Send>(amount: T, method: LeakMethod) -> Result<(), LeakError> { + leak(amount, method) } diff --git a/src/parse.rs b/src/parse.rs index c5521d6..d6e5dfa 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,16 +1,45 @@ use std::str::FromStr; -use crate::{PissError, PissAmount}; +use crate::{LeakError, LeakAmount}; -impl From for PissAmount -where T: Into { - fn from(num: T) -> Self { - Self { - to_piss: num.into() - } - } +macro_rules! from_num { + ($t:ty) => { + impl From<$t> for LeakAmount { + fn from(num: $t) -> Self { + Self { + to_leak: num as u128 + } + } + } + + impl From> for LeakAmount { + fn from(vec: Vec<$t>) -> Self { + let mut amount = 0; + for i in vec { + amount += i as u128; + } + Self { + to_leak: amount + } + } + } + }; } -fn parse_suffix(s: &str) -> Result { +from_num!(u128); +from_num!(u64); +from_num!(u32); +from_num!(u16); +from_num!(u8); +from_num!(i128); +from_num!(i64); +from_num!(i32); +from_num!(i16); +from_num!(i8); +from_num!(f32); +from_num!(f64); +from_num!(bool); + +fn parse_suffix(s: &str) -> Result { Ok(match s { // nepal "k" | "kb" => 1_000, "m" | "mb" => 1_000_000, @@ -33,39 +62,40 @@ fn parse_suffix(s: &str) -> Result { "ri" | "rib" => 0x0400_0000_0000_0000_0000_0000, "qi" | "qib" => 0x0010_0000_0000_0000_0000_0000_0000, "" | "b" => 1, // uwu - _ => return Err(PissError::InvalidSuffix(s.into())) // such nepal + _ => return Err(LeakError::InvalidSuffix(s.into())) // such nepal }) } -fn parse_file_size(s: &str) -> Result { +fn parse_file_size(s: &str) -> Result { let mut end = 0; for (i, c) in s.char_indices() { - if c.is_ascii_digit() || c == '.' { continue; } end = i; - break; + if !c.is_ascii_digit() && c != '.' { break; } + } + + if end == 0 { + if let Some(c) = s.chars().nth(0) { + return Err(LeakError::Unexpected(c)) + } } let num_text = &s[..end]; let suffix_text = &s[end..]; let Ok(num) = num_text.parse::() else { - return Err(PissError::InvalidNumber(num_text.into())) + return Err(LeakError::InvalidNumber(num_text.into())) }; - if num <= 0f64 { - return Err(PissError::NumberNotPositive) - } - let multiplier = parse_suffix(suffix_text)?; - Ok(PissAmount { - to_piss: (num * multiplier as f64) as u128 + Ok(LeakAmount { + to_leak: (num * multiplier as f64) as u128 }) } -impl FromStr for PissAmount { - type Err = PissError; +impl FromStr for LeakAmount { + type Err = LeakError; fn from_str(s: &str) -> Result { - parse_file_size(s) + parse_file_size(s.to_lowercase().as_str()) } }