hardened-malloc 16.0.2026060601

Global allocator using GrapheneOS allocator
//
// hardened-malloc: Global allocator using GrapheneOS allocator
// tests/tests.rs: Integration tests for hardened-malloc
//
// Copyright (c) 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: MIT

use std::alloc::{GlobalAlloc, Layout};

#[global_allocator]
static ALLOC: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;

#[repr(C, align(32))]
struct Aligned32 {
    data: [u8; 32],
}

#[repr(C, align(64))]
struct Aligned64 {
    data: [u8; 64],
}

#[test]
fn test_alloc_1() {
    let layout = Layout::new::<Aligned32>();
    assert_eq!(layout.align(), 32);
    assert_eq!(layout.size(), 32);

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 32, 0);

            ptr.write_bytes(0xAA, 32);

            let slice = std::slice::from_raw_parts(ptr, 32);
            assert!(slice.iter().all(|&b| b == 0xAA));

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_2() {
    let layout = Layout::new::<Aligned64>();
    assert_eq!(layout.align(), 64);
    assert_eq!(layout.size(), 64);

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 64, 0);

            ptr.write_bytes(0xBB, 64);
            let slice = std::slice::from_raw_parts(ptr, 64);
            assert!(slice.iter().all(|&b| b == 0xBB));

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_3() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc_zeroed(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 32, 0);

            let slice = std::slice::from_raw_parts(ptr, 32);
            assert!(slice.iter().all(|&b| b == 0));

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_4() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let initial_addr = ptr as usize;
            assert_eq!(initial_addr % 32, 0);

            ptr.write_bytes(0xCC, 32);

            let new_size = 128;
            let new_ptr = ALLOC.realloc(ptr, layout, new_size);
            assert!(!new_ptr.is_null());

            let new_addr = new_ptr as usize;
            assert_eq!(new_addr % 32, 0);

            new_ptr.write_bytes(0xDD, new_size);
            let slice = std::slice::from_raw_parts(new_ptr, new_size);
            assert!(slice.iter().all(|&b| b == 0xDD));

            ALLOC.dealloc(new_ptr, Layout::from_size_align_unchecked(new_size, 32));
        }
    }
}

#[test]
fn test_alloc_5() {
    let layout = Layout::new::<Aligned64>();

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let initial_addr = ptr as usize;
            assert_eq!(initial_addr % 64, 0);

            let new_size = 256;
            let new_ptr = ALLOC.realloc(ptr, layout, new_size);
            assert!(!new_ptr.is_null());

            let new_addr = new_ptr as usize;
            assert_eq!(new_addr % 64, 0);

            ALLOC.dealloc(new_ptr, Layout::from_size_align_unchecked(new_size, 64));
        }
    }
}

#[test]
fn test_alloc_6() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..1000 {
        unsafe {
            let mut ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());
            assert_eq!(ptr as usize % 32, 0);

            for new_size in [64, 128, 256, 512] {
                ptr = ALLOC.realloc(ptr, layout, new_size);
                assert!(!ptr.is_null());
                let addr = ptr as usize;
                assert_eq!(addr % 32, 0);
            }

            ALLOC.dealloc(ptr, Layout::from_size_align_unchecked(512, 32));
        }
    }
}

#[test]
fn test_alloc_7() {
    let mut ptrs = Vec::new();
    let layout = Layout::new::<Aligned32>();

    for i in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 32, 0);

            (ptr as *mut u32).write_volatile(i as u32);

            ptrs.push(ptr);
        }
    }

    for (i, &ptr) in ptrs.iter().enumerate() {
        unsafe {
            let val = (ptr as *const u32).read_volatile();
            assert_eq!(val, i as u32);
        }
    }

    unsafe {
        for &ptr in &ptrs {
            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_8() {
    for align in [32, 64, 128, 256] {
        let layout = Layout::from_size_align(64, align).unwrap();

        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % align, 0);

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_9() {
    let layout = Layout::from_size_align(64, 32).unwrap();
    assert_eq!(layout.align(), 32);
    assert_eq!(layout.size(), 64);

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 32, 0);

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_10() {
    for _ in 0..1000 {
        let layout = Layout::new::<Aligned32>();

        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());

            let addr = ptr as usize;
            assert_eq!(addr % 32, 0);

            ALLOC.dealloc(ptr, layout);
        }
    }
}

#[test]
fn test_alloc_11() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.realloc(core::ptr::null_mut(), layout, 64);
            assert!(!ptr.is_null());
            assert_eq!(ptr as usize % 32, 0);
            ALLOC.dealloc(ptr, Layout::from_size_align_unchecked(64, 32));
        }
    }
}

#[test]
fn test_alloc_12() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..1000 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());
            let result = ALLOC.realloc(ptr, layout, 0);
            assert!(result.is_null());
        }
    }
}

#[test]
fn test_alloc_13() {
    let layout = Layout::new::<Aligned32>();

    for _ in 0..100 {
        unsafe {
            let ptr = ALLOC.alloc(layout);
            assert!(!ptr.is_null());
            assert_eq!(ptr as usize % 32, 0);

            ptr.write_bytes(0xAA, 32);

            let shrunk = ALLOC.realloc(ptr, layout, 16);
            assert!(!shrunk.is_null());
            assert_eq!(shrunk as usize % 32, 0);

            let slice = std::slice::from_raw_parts(shrunk, 16);
            assert!(slice.iter().all(|&b| b == 0xAA));

            ALLOC.dealloc(shrunk, Layout::from_size_align_unchecked(16, 32));
        }
    }
}