Double Drop with #![deny(rust_2024_compatibility)] #134482
Closed
Description
I had a custom Rc that was doubly freeing memory because Drop was being called more times than it should.
After a little bit of testing I think this is a small enough Minimal-Reproducible-Example:
playground
// ---------------------------------------- //
// If commented, it only calls Drop 2 times //
// If not commented, it calls Drop 3 times //
// ---------------------------------------- //
#![deny(rust_2024_compatibility)]
use std::backtrace::Backtrace;
struct Guard();
impl Clone for Guard {
fn clone(&self) -> Self {
Self()
}
}
impl Drop for Guard {
fn drop(&mut self) {
println!("Drop!");
eprintln!("Drop at {}!", Backtrace::force_capture());
}
}
fn main() {
let _ = method_1(Guard());
}
fn method_1(g: Guard) -> Result<String, ()> {
// ----------------------- //
// This calls Drop 2 times //
// ----------------------- //
// let argument = &g.clone();
// match method_2(argument) {
// Ok(str) => Ok(str),
// Err(err) => Err(err),
// }
// --- //
// ----------------------- //
// This calls Drop 3 times //
// ----------------------- //
match method_2(&g.clone()) {
Ok(str) => Ok(str),
Err(err) => Err(err),
}
}
fn method_2(_: &Guard) -> Result<String, ()> {
panic!("Method 2 panics!");
}
I expected to see this happen: Drop is called twice.
Instead, this happened: Drop is called 3 times.
Notes
- The return type doesn't need to be a
Result<String, ()>
It seems that it happens as long as it is an enum in which one arm has a non-Copy
type.
So it also happens if the return type is
enum CustomEnum {
MyArm(Vec<u32>),
}
- The problems seems to happen regardless of the presence of the
--release
flag - As seen in the backtrace below, the first drop is called at the end of the enum match, and the other two are called at the end of method_1
Meta
rustc --version --verbose
:
rustc 1.85.0-nightly (a4cb3c831 2024-12-17)
binary: rustc
commit-hash: a4cb3c831823d9baa56c3d90514b75b2660116fa
commit-date: 2024-12-17
host: x86_64-pc-windows-msvc
release: 1.85.0-nightly
LLVM version: 19.1.5
Backtrace
Reduced stderr from the playground:
Running `target/debug/playground`
thread 'main' panicked at src/main.rs:51:5:
Method 2 panics!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Drop at 0: <playground::Guard as core::ops::drop::Drop>::drop
at ./src/main.rs:18:33
1: core::ptr::drop_in_place<playground::Guard>
at ./.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:522:1
2: playground::method_1
at ./src/main.rs:46:5
3: [...]
Drop at 0: <playground::Guard as core::ops::drop::Drop>::drop
at ./src/main.rs:18:33
1: core::ptr::drop_in_place<playground::Guard>
at ./.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:522:1
2: playground::method_1
at ./src/main.rs:47:1
3: [...]
Drop at 0: <playground::Guard as core::ops::drop::Drop>::drop
at ./src/main.rs:18:33
1: core::ptr::drop_in_place<playground::Guard>
at ./.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:522:1
2: playground::method_1
at ./src/main.rs:47:1
3: [...]
Metadata
Assignees
Labels
Area: The 2024 editionCategory: This is a bug.Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessLint: tail_expr_drop_orderCritical priorityStatus: a bisection has been found for this issueStatus: A Minimal Complete and Verifiable Example has been found for this issueRelevant to the compiler team, which will review and decide on the PR/issue.Performance or correctness regression from stable to beta.
Activity