Skip to content

Support for custom allocator in miri #1207

@jacob-hughes

Description

@jacob-hughes

If I understand correctly, Miri replaces the allocator, even when the #[global_allocator] attribute is used to specify a custom allocator. Unfortunately, this can lead to Miri thinking that a program invokes UB when it does not.

In the following example, I implement a custom allocator where alloc reserves the first machine word in each block in order to store a header, it then returns a pointer to the next address. Since Miri replaces this with its own allocator, dereferencing a pointer to the header's offset will be out-of-bounds.

#![feature(alloc_layout_extra)]
use std::alloc::{GlobalAlloc, Layout, System};
use std::mem::size_of;

#[global_allocator]
static ALLOCATOR: Allocator = Allocator {};

const HEADER: usize = 42;

struct Allocator {}

unsafe impl GlobalAlloc for Allocator {
    // Allocate a block with a usize sized header, and return a pointer to the
    // next address.
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let (new_layout, _) = Layout::new::<usize>().extend(layout).unwrap();
        let base_ptr = System.alloc(new_layout) as *mut usize;
        ::std::ptr::write(base_ptr, HEADER);
        base_ptr.add(1) as *mut u8
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        let (new_layout, _) = Layout::new::<usize>().extend(layout).unwrap();
        let base_ptr = (ptr as *mut usize).wrapping_sub(1) as *mut u8;
        System.dealloc(base_ptr, new_layout);
    }
}

fn main() {
    let block = Box::into_raw(Box::new(123_usize));

    // Get a pointer to the block header using integer arithmetic.
    let header_ptr = (block as usize - size_of::<usize>()) as *mut usize;
    assert_eq!(unsafe { *header_ptr }, HEADER); // Miri error: dangling pointer dereference

    // Get a pointer to the block header using wrapping_sub.
    let header_ptr = block.wrapping_sub(1);
    assert_eq!(unsafe { *header_ptr }, HEADER); // Miri error: overflowing in-bounds pointer arithmetic

    unsafe { Box::from_raw(block) };
}

Running this under miri causes an evaluation error upon the first misuse of header_ptr:

   Compiling playground v0.0.1 (/playground)
error: Miri evaluation error: dangling pointer was dereferenced
  --> src/main.rs:34:25
   |
34 |     assert_eq!(unsafe { *header_ptr }, HEADER); // Miri error: dangling pointer dereference
   |                         ^^^^^^^^^^^ dangling pointer was dereferenced
   |

Playground link

Is this kind of support possible? Alternatively, perhaps if suppression support landed this may be an ideal use-case. [issue #788]

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-shimsArea: This affects the external function shimsC-enhancementCategory: a PR with an enhancement or an issue tracking an accepted enhancement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions