Skip to content

dyn Allocator together with Allocator + PartialEq safety requirements leads to unsoundness #156917

Description

@maxdexh

#156882 introduces new requirements that state that "Implementors of Allocator which are also PartialEq must ensure equality guarantees that memory allocated with one can be freed with the other".

However, safe code can trick functions relying on this by upcasting to a wrapper trait if Allocator is dyn-compatible:

#![feature(allocator_api)]

use std::alloc::{Allocator, Global, Layout, System};

// upstream function using PartialEq guarantees
fn safe_func<A: Allocator + PartialEq + ?Sized>(x: &A, y: &A) {
    let layout = Layout::from_size_align(10000, 512).unwrap();
    let block = x.allocate(layout).unwrap();
    assert_eq!(x, y);
    // SAFETY:
    // - Deallocating `block` with `x` is trivially safe
    // - x == y, so the allocators can be used interchangably
    unsafe { y.deallocate(block.cast(), layout) };
}

// downstream crate without `unsafe`
trait NewTrait: Allocator {}
impl<A: Allocator> NewTrait for A {}

impl PartialEq for dyn NewTrait + '_ {
    fn eq(&self, _: &Self) -> bool {
        true
    }
}

fn confuse_allocators<A: Allocator, B: Allocator>(a: &A, b: &B) {
    safe_func::<dyn NewTrait>(a, b);

    // Version that also works without `+ ?Sized`:
    safe_func::<&dyn NewTrait>(&(a as _), &(b as _));
}

use jemallocator::Jemalloc;

#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;

fn main() {
    confuse_allocators(&Global, &System);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-allocatorsArea: Custom and system allocatorsA-dyn-compatibilityArea: Dyn compatibility (formerly: object safety)A-dyn-traitArea: trait objects, vtable layoutC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions