Skip to content

Box sometimes forgets to drop its allocator when the Box is conditionally initialized. #131082

@theemathas

Description

@theemathas

I tried this code:

#![feature(allocator_api)]

use std::alloc::{Allocator, AllocError, Layout, Global};
use std::ptr::NonNull;

struct LoudDropAllocator;

unsafe impl Allocator for LoudDropAllocator {
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
        Global.allocate(layout)
    }
    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
        Global.deallocate(ptr, layout);
    }
}
impl Drop for LoudDropAllocator {
    fn drop(&mut self) {
        println!("dropping allocator...");
    }
}

struct HasDrop;
impl Drop for HasDrop {
    fn drop(&mut self) {}
}

fn foo() {
    println!("foo()");
    let b = Box::new_in(HasDrop, LoudDropAllocator);
    if true {
        drop(*b);
    } else {
        drop(b);
    }
}

fn bar() {
    println!("bar()");
    let b = Box::new_in(HasDrop, LoudDropAllocator);
    if true {
        drop(*b);
    } else {
        // drop(b);
    }
}

fn main() {
    foo();
    bar();
}

I expected the program to output:

foo()
dropping allocator...
bar()
dropping allocator...

Instead it output:

foo()
bar()
dropping allocator...

Seems like there's something wrong with the drop flags.

Making HasDrop not implement Drop causes the program to behave as expected.

Meta

Reproducible on the playground with version 1.83.0-nightly (2024-09-30 fb4aebddd18d258046dd)

Metadata

Metadata

Assignees

Labels

A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-allocatorsArea: Custom and system allocatorsA-boxArea: Our favorite opsem complicationC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions