rust-lang / rust-lang/rust

Shallow box drop creates mutable reference to memory that has already been moved away

Open
#154,089 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-destructors C-bug needs-triage
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code like this

fn foo<T>(x: Box<T>) {
    std::mem::forget(*x);
}

generates MIR like this

    bb1: {
        _4 = &mut _1;
        _5 = <Box<T> as Drop>::drop(move _4) -> [return: bb3, unwind continue];
    }

This is a call of the drop function on Box (which usually cannot be directly called), it is not a drop terminator.

The problem with this is that the box contents have already been moved out at this point. If validity is recursive through Box and &mut, that means this call is UB because the validity invariant of T may no longer hold. This currently causes tons of UB in safe code when turning on Miri's recursive validation mode:

error: Undefined Behavior: constructing invalid value at .<deref>.<deref>.<dyn-downcast>.<captured-var(x)>: encountered uninitialized memory, but expected an integer
    --> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/library/alloc/src/boxed.rs:2240:51
     |
2240 |         <F as FnOnce<Args>>::call_once(*self, args)
     |                                                   ^ Undefined Behavior occurred here
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: stack backtrace:
             0: <std::boxed::Box<dyn std::ops::FnOnce() -> i32> as std::ops::FnOnce<()>>::call_once
                 at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/library/alloc/src/boxed.rs:2240:51: 2240:52
             1: boxed_fn_once
                 at tests/pass/closures.rs:48:5: 48:8
             2: main
                 at tests/pass/closures.rs:118:9: 121:12

Also see https://github.com/rust-lang/unsafe-code-guidelines/issues/412
Cc @rust-lang/opsem

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the example and examining its generated MIR, then run the affected case with Miri's recursive validation mode. Inspect alloc/src/boxed.rs around line 2240 and tests/pass/closures.rs around the cited locations. Done means establishing corrected handling for the shallow box drop and adding coverage that no invalid reference or UB is reported.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.