Repository navigation
Zpolonius=next soundness bug: UB caused by liveness detection #160670
Description
I tried this code:
#![forbid(unsafe_code)]
use std::fmt::Debug;
trait HasArg { type Arg: Debug; }
impl<'a> HasArg for fn(&'a u8) { type Arg = &'a u8; }
struct D<T: HasArg>(T, Option<T::Arg>);
impl<T: HasArg> Drop for D<T> {
fn drop(&mut self) { println!("{:?}", self.1); }
}
fn f(_: &u8) {}
fn mk<'a>(r: &'a u8) -> D<fn(&'a u8)> { D(f as fn(&'a u8), Some(r)) }
fn main() {
let b = Box::new(42u8);
let d;
d = mk(&*b);
drop(b);
} // D::drop prints *(&*b) after the Box was freedcompiled with -Zpolonius=next.
I expected to see this happen: the program is rejected
Instead, this happened: -Zpolonius=next accepts it and gives a UB. Standard build rejects it.
Meta
rustc --version --verbose:
rustc 1.99.0-nightly (1ed2df61a 2026-08-04)
LLM-written explanation of what it thinks is happening
Summary: -Zpolonius=next propagates a loan from (R, P) to
(R, succ(P)) only along a liveness edge, and the direction of that edge
comes from the recorded variance of R. For a local that is only ever
drop-live, the variance is extracted from the dropck kinds instead of the
local's type — and for an ADT with a user Drop impl those are the generic
arguments verbatim. A lifetime that is contravariant in the generic argument
but reachable (invariantly) through an associated-type projection field gets a
Backward edge, i.e. no forward propagation at all, so the loan is live
nowhere on the local's drop-live range and a conflicting move is accepted.
What goes wrong
compiler/rustc_borrowck/src/polonius/liveness_constraints.rs:66-74—
covariant ⇒Forward, contravariant ⇒Backward, invariant ⇒
Bidirectional.compiler/rustc_borrowck/src/polonius/constraints.rs:271-287—
compute_forward_successorreturnsNonefor aBackwardregion: it has
no forward successor.- Variances are recorded by
VarianceExtractoron every value handed to
make_all_regions_live(type_check/liveness/trace.rs:625-631).
let d; d = mk(..); has no initializer, hence no FakeRead(ForLet), hence
no Use appearance at all — only Defs and Drops — so compute_for_all_locals
skips the use-live path and only add_drop_live_facts_for
(trace.rs:547-600) runs. That function does not feed make_all_regions_live
the local's type D<fn(&'?4 u8)>; it feeds each dropck kind (trace.rs:590-591),
and for an ADT with a user Drop impl, destructor_constraints yields the
ADT's generic arguments verbatim: fn(&'?4 u8). There '?4 is
contravariant ⇒ Backward ⇒ no forward liveness edge ⇒ the loan of *b is
live nowhere on d's drop-live range ⇒ drop(b) is accepted.
But D really stores a &'?4 u8 through the projection field
<T as HasArg>::Arg (which makes T invariant in D), and its destructor
reads it. The variance of the kind is not the variance of the stored
data.
Controls (all on the unfixed compiler):
| variant | result |
|---|---|
| as above, default borrowck | rejected E0505 |
as above, -Zpolonius (legacy) |
rejected E0505 |
give d an initializer (let d = mk(&*b);) |
rejected E0505 under =next too (use-liveness records the local's type, invariant) |
remove the Drop impl |
accepted everywhere, sound (no destructor reads the field) |
Fix direction: record the regions of dropck kinds as invariant
(Bidirectional) in add_drop_live_facts_for, rather than reusing the
syntactic variance extractor on the kind. Drop executes arbitrary user code
on the stored data; directionality derived from the kind's surface syntax is
not sound for it.
Activity
maxdexh commentedon Aug 7, 2026
Simplified example that segfaults (playground)
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Rollup merge of rust-lang#161305 - amandasystems:issue-160670, r=lqd,…
Unrolled build for #161305 in rollup 162907