lleeaakk
This commit is contained in:
parent
665e500fe7
commit
346bac811d
6 changed files with 134 additions and 51 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -2,15 +2,15 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leak_memory"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.146"
|
version = "0.2.146"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urine"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
[package]
|
[package]
|
||||||
name = "urine"
|
name = "leak_memory"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
authors = ["Tyler Murphy <tylerm@tylerm.dev>"]
|
||||||
edition = "2021"
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
7
LICENSE
Normal file
7
LICENSE
Normal file
|
@ -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.
|
31
README.md
Normal file
31
README.md
Normal file
|
@ -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::<LeakAmount>().unwrap(), LeakMethod::Rust);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Compilation
|
||||||
|
|
||||||
|
dont
|
49
src/lib.rs
49
src/lib.rs
|
@ -1,33 +1,35 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use libc::malloc;
|
use libc::malloc;
|
||||||
use std::fmt::{Result, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
pub mod parse;
|
mod parse;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PissError {
|
pub enum LeakError {
|
||||||
|
Unexpected(char),
|
||||||
InvalidSuffix(String),
|
InvalidSuffix(String),
|
||||||
InvalidNumber(String),
|
InvalidNumber(String),
|
||||||
NumberNotPositive
|
NumberNotPositive
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PissError {
|
impl Display for LeakError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::InvalidSuffix(s) => write!(f, "I cannot piss the suffix {s:?}"),
|
Self::Unexpected(c) => write!(f, "Unexpected character: '{c}'"),
|
||||||
Self::InvalidNumber(s) => write!(f, "I cannot piss the invalid number {s:?}"),
|
Self::InvalidSuffix(s) => write!(f, "Invalid file size suffix: '{s}'"),
|
||||||
Self::NumberNotPositive => write!(f, "I cannot piss nonexistent memory")
|
Self::InvalidNumber(s) => write!(f, "Invalid number: '{s}'"),
|
||||||
|
Self::NumberNotPositive => write!(f, "Cannot leak negative memory")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub struct PissAmount {
|
pub struct LeakAmount {
|
||||||
to_piss: u128
|
to_leak: u128
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum Toliet {
|
pub enum LeakMethod {
|
||||||
Rust,
|
Rust,
|
||||||
Lazy,
|
Lazy,
|
||||||
Unsafe
|
Unsafe
|
||||||
|
@ -42,7 +44,7 @@ thread_local!(static TOLIET: RefCell<Vec<Vec<u8>>> = RefCell::new(Vec::new()));
|
||||||
fn leak_lazy(amount: usize) {
|
fn leak_lazy(amount: usize) {
|
||||||
TOLIET.with(|t| {
|
TOLIET.with(|t| {
|
||||||
t.borrow_mut().push(Vec::<u8>::with_capacity(amount));
|
t.borrow_mut().push(Vec::<u8>::with_capacity(amount));
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leak_unsafe(amount: usize) {
|
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 {
|
match method {
|
||||||
Toliet::Rust => leak_rust(amount),
|
LeakMethod::Rust => leak_rust(amount),
|
||||||
Toliet::Lazy => leak_lazy(amount),
|
LeakMethod::Lazy => leak_lazy(amount),
|
||||||
Toliet::Unsafe => leak_unsafe(amount),
|
LeakMethod::Unsafe => leak_unsafe(amount),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn leak<T: Into<PissAmount>>(amount: T, method: Toliet) {
|
pub fn leak<T: Into<LeakAmount>>(amount: T, method: LeakMethod) -> Result<(), LeakError> {
|
||||||
let num: u128 = amount.into().to_piss;
|
let num: u128 = amount.into().to_leak;
|
||||||
|
|
||||||
|
if num <= 0 {
|
||||||
|
return Err(LeakError::NumberNotPositive)
|
||||||
|
}
|
||||||
|
|
||||||
let count = num / usize::MAX as u128;
|
let count = num / usize::MAX as u128;
|
||||||
|
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
|
@ -68,8 +75,10 @@ pub fn leak<T: Into<PissAmount>>(amount: T, method: Toliet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leak_match((num % usize::MAX as u128) as usize, method);
|
leak_match((num % usize::MAX as u128) as usize, method);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn leak_async<T: Into<PissAmount>>(amount: T, method: Toliet) {
|
pub async fn leak_async<T: Into<LeakAmount> + Send>(amount: T, method: LeakMethod) -> Result<(), LeakError> {
|
||||||
leak(amount, method);
|
leak(amount, method)
|
||||||
}
|
}
|
||||||
|
|
70
src/parse.rs
70
src/parse.rs
|
@ -1,16 +1,45 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use crate::{PissError, PissAmount};
|
use crate::{LeakError, LeakAmount};
|
||||||
|
|
||||||
impl<T> From<T> for PissAmount
|
macro_rules! from_num {
|
||||||
where T: Into<u128> {
|
($t:ty) => {
|
||||||
fn from(num: T) -> Self {
|
impl From<$t> for LeakAmount {
|
||||||
|
fn from(num: $t) -> Self {
|
||||||
Self {
|
Self {
|
||||||
to_piss: num.into()
|
to_leak: num as u128
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<$t>> 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<u128, PissError> {
|
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<u128, LeakError> {
|
||||||
Ok(match s { // nepal
|
Ok(match s { // nepal
|
||||||
"k" | "kb" => 1_000,
|
"k" | "kb" => 1_000,
|
||||||
"m" | "mb" => 1_000_000,
|
"m" | "mb" => 1_000_000,
|
||||||
|
@ -33,39 +62,40 @@ fn parse_suffix(s: &str) -> Result<u128, PissError> {
|
||||||
"ri" | "rib" => 0x0400_0000_0000_0000_0000_0000,
|
"ri" | "rib" => 0x0400_0000_0000_0000_0000_0000,
|
||||||
"qi" | "qib" => 0x0010_0000_0000_0000_0000_0000_0000,
|
"qi" | "qib" => 0x0010_0000_0000_0000_0000_0000_0000,
|
||||||
"" | "b" => 1, // uwu
|
"" | "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<PissAmount, PissError> {
|
fn parse_file_size(s: &str) -> Result<LeakAmount, LeakError> {
|
||||||
let mut end = 0;
|
let mut end = 0;
|
||||||
for (i, c) in s.char_indices() {
|
for (i, c) in s.char_indices() {
|
||||||
if c.is_ascii_digit() || c == '.' { continue; }
|
|
||||||
end = i;
|
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 num_text = &s[..end];
|
||||||
let suffix_text = &s[end..];
|
let suffix_text = &s[end..];
|
||||||
|
|
||||||
let Ok(num) = num_text.parse::<f64>() else {
|
let Ok(num) = num_text.parse::<f64>() 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)?;
|
let multiplier = parse_suffix(suffix_text)?;
|
||||||
|
|
||||||
Ok(PissAmount {
|
Ok(LeakAmount {
|
||||||
to_piss: (num * multiplier as f64) as u128
|
to_leak: (num * multiplier as f64) as u128
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for PissAmount {
|
impl FromStr for LeakAmount {
|
||||||
type Err = PissError;
|
type Err = LeakError;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
parse_file_size(s)
|
parse_file_size(s.to_lowercase().as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue