Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into windows
Browse files Browse the repository at this point in the history
Additionally update Windows implementation to compile.
  • Loading branch information
alexcrichton committed Jan 28, 2024
2 parents 3c2dde8 + 9a0e6a1 commit b36cdae
Show file tree
Hide file tree
Showing 16 changed files with 471 additions and 175 deletions.
33 changes: 29 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
rust: [stable, beta, nightly]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Install Rust (
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
- run: cargo test
Expand All @@ -26,7 +26,7 @@ jobs:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt -- --check
Expand All @@ -35,7 +35,7 @@ jobs:
name: WebAssembly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup target add wasm32-unknown-unknown
- run: cargo build --target wasm32-unknown-unknown
Expand All @@ -45,7 +45,32 @@ jobs:
name: external-platform
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable && rustup default stable && rustup target add x86_64-fortanix-unknown-sgx
- run: cargo build --target x86_64-fortanix-unknown-sgx

fuzz:
name: Build Fuzzers
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update nightly && rustup default nightly
- run: cargo install cargo-fuzz
- run: cargo fuzz build --dev

miri:
name: Miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Miri
run: |
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup
- name: Test with Miri
run: cargo miri test
env:
MIRIFLAGS: -Zmiri-tree-borrows
36 changes: 21 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dlmalloc"
version = "0.2.3"
version = "0.2.4"
authors = ["Alex Crichton <[email protected]>"]
license = "MIT/Apache-2.0"
readme = "README.md"
Expand All @@ -10,6 +10,13 @@ documentation = "https://docs.rs/dlmalloc"
description = """
A Rust port of the dlmalloc allocator
"""
edition.workspace = true

[workspace]
members = ['fuzz']

[workspace.package]
edition = '2021'

[package.metadata.docs.rs]
features = ['global']
Expand All @@ -25,21 +32,20 @@ libc = { version = "0.2", default-features = false }
# `src/tools/rustc-std-workspace` folder
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
compiler_builtins = { version = '0.1.0', optional = true }
once_cell = "1.9.0"
cfg-if = "1.0"
[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.33.0", features = [
"alloc",
"Win32_System_Memory",
"Win32_Foundation",
"Win32_System_Threading",
"Win32_Security",
"Win32_System_Diagnostics",
"Win32_System_Diagnostics_Debug"
] }

[dev-dependencies ]
rand = "0.3"

[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.52.0"
features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_Threading",
"Win32_System_SystemInformation",
]

[dev-dependencies]
arbitrary = "1.3.2"
rand = { version = "0.8", features = ['small_rng'] }

[profile.release]
debug-assertions = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A port of [dlmalloc] to Rust.

[Documentation](https://docs.rs/dlmalloc)

[dlmalloc]: http://gee.cs.oswego.edu/dl/html/malloc.html
[dlmalloc]: https://gee.cs.oswego.edu/dl/html/malloc.html

## Why dlmalloc?

Expand Down
2 changes: 2 additions & 0 deletions fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
corpus
artifacts
19 changes: 19 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "dlmalloc-fuzz"
version = "0.0.1"
publish = false
edition.workspace = true

[package.metadata]
cargo-fuzz = true

[dependencies]
arbitrary = "1.3.2"
dlmalloc = { path = '..' }
libfuzzer-sys = "0.4.7"

[[bin]]
name = "alloc"
path = "fuzz_targets/alloc.rs"
test = false
bench = false
8 changes: 8 additions & 0 deletions fuzz/fuzz_targets/alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![no_main]

use arbitrary::Unstructured;
use libfuzzer_sys::fuzz_target;

fuzz_target!(|bytes: &[u8]| {
let _ = dlmalloc_fuzz::run(&mut Unstructured::new(bytes));
});
108 changes: 108 additions & 0 deletions fuzz/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use arbitrary::{Result, Unstructured};
use dlmalloc::Dlmalloc;
use std::cmp;

const MAX_ALLOCATED: usize = 100 << 20; // 100 MB

pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
let mut a = Dlmalloc::new();
let mut ptrs = Vec::new();
let mut allocated = 0;
unsafe {
while u.arbitrary()? {
// If there are pointers to free then have a chance of deallocating
// a pointer. Try not to deallocate things until there's a "large"
// working set but afterwards give it a 50/50 chance of allocating
// or deallocating.
let free = match ptrs.len() {
0 => false,
0..=10_000 => u.ratio(1, 3)?,
_ => u.arbitrary()?,
};
if free {
let idx = u.choose_index(ptrs.len())?;
let (ptr, size, align) = ptrs.swap_remove(idx);
allocated -= size;
a.free(ptr, size, align);
continue;
}

// 1/100 chance of reallocating a pointer to a different size.
if ptrs.len() > 0 && u.ratio(1, 100)? {
let idx = u.choose_index(ptrs.len())?;
let (ptr, size, align) = ptrs.swap_remove(idx);

// Arbitrarily choose whether to make this allocation either
// twice as large or half as small.
let new_size = if u.arbitrary()? {
u.int_in_range(size..=size * 2)?
} else if size > 10 {
u.int_in_range(size / 2..=size)?
} else {
continue;
};
if allocated + new_size - size > MAX_ALLOCATED {
ptrs.push((ptr, size, align));
continue;
}
allocated -= size;
allocated += new_size;

// Perform the `realloc` and assert that all bytes were copied.
let mut tmp = Vec::new();
for i in 0..cmp::min(size, new_size) {
tmp.push(*ptr.offset(i as isize));
}
let ptr = a.realloc(ptr, size, align, new_size);
assert!(!ptr.is_null());
for (i, byte) in tmp.iter().enumerate() {
assert_eq!(*byte, *ptr.offset(i as isize));
}
ptrs.push((ptr, new_size, align));
}

// Aribtrarily choose a size to allocate as well as an alignment.
// Enable small sizes with standard alignment happening a fair bit.
let size = if u.arbitrary()? {
u.int_in_range(1..=128)?
} else {
u.int_in_range(1..=128 * 1024)?
};
let align = if u.ratio(1, 10)? {
1 << u.int_in_range(3..=8)?
} else {
8
};

if size + allocated > MAX_ALLOCATED {
continue;
}
allocated += size;

// Choose arbitrarily between a zero-allocated chunk and a normal
// allocated chunk.
let zero = u.ratio(1, 50)?;
let ptr = if zero {
a.calloc(size, align)
} else {
a.malloc(size, align)
};
for i in 0..size {
if zero {
assert_eq!(*ptr.offset(i as isize), 0);
}
*ptr.offset(i as isize) = 0xce;
}
ptrs.push((ptr, size, align));
}

// Deallocate everythign when we're done.
for (ptr, size, align) in ptrs {
a.free(ptr, size, align);
}

a.destroy();
}

Ok(())
}
Loading

0 comments on commit b36cdae

Please sign in to comment.