Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jobs:
- os: ubuntu-latest
rust: stable
target: wasm32-wasip1
- os: ubuntu-latest
rust: stable
target: i686-unknown-linux-gnu
gcc_target: i686-linux-gnu
steps:
- uses: actions/checkout@v4
- run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
Expand All @@ -40,6 +44,17 @@ jobs:
- run: echo CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime >> $GITHUB_ENV
if: matrix.target == 'wasm32-wasip1'

- name: Install cross-compilation tools
run: |
set -ex

sudo apt-get update
sudo apt-get install -y gcc-${{ matrix.gcc_target }}

upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
echo CARGO_TARGET_${upcase}_LINKER=${{ matrix.gcc_target }}-gcc >> $GITHUB_ENV
if: matrix.gcc_target != ''

- run: cargo test
- run: cargo test --features debug
- run: cargo test --features global
Expand Down
25 changes: 20 additions & 5 deletions src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,29 @@ unsafe impl Allocator for System {
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let pages = size.div_ceil(self.page_size());
let prev = wasm::memory_grow(0, pages);

// If the allocation failed, meaning `prev` is -1 or
// `usize::max_value()`, then return null.
if prev == usize::max_value() {
return (ptr::null_mut(), 0, 0);
}
(
(prev * self.page_size()) as *mut u8,
pages * self.page_size(),
0,
)

let prev_page = prev * self.page_size();
let base_ptr = prev_page as *mut u8;
let size = pages * self.page_size();

// Additionally check to see if we just allocated the final bit of the
// address space. In such a situation it's not valid in Rust for a
// pointer to actually wrap around to from the top of the address space
// to 0, so it's not valid to allocate the entire region. Fake the last
// few bytes as being un-allocated meaning that the actual size of this
// allocation won't be page aligned, which should be handled by
// dlmalloc.
if prev_page.wrapping_add(size) == 0 {
return (base_ptr, size - 16, 0);
}

(base_ptr, size, 0)
}

fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
Expand Down
28 changes: 28 additions & 0 deletions tests/eat_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// This test requires the `global` feature, and then also require a 32-bit
// platform as otherwise exhausting the address space on 64-bit platforms is
// unreasonable.
#![cfg(all(feature = "global", target_pointer_width = "32"))]

use std::mem;

#[global_allocator]
static A: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc;

fn get_vec_allocated_near_end_of_address_space() -> Vec<u8> {
// Reserve a 1.5 GiB outer vector, to OOM faster
let mut test_vector: Vec<Vec<u8>> = Vec::with_capacity(2usize.pow(27));

// Allocate 1KiB vectors until we run out of memory
loop {
let mut inner_vector = vec![];
if inner_vector.try_reserve_exact(1024).is_err() {
return mem::take(test_vector.last_mut().unwrap());
};
test_vector.push(inner_vector);
}
}

#[test]
fn eat_memory() {
get_vec_allocated_near_end_of_address_space();
}
Loading