Repository navigation
Open
Labels
A-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)C-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessNLL-poloniusIssues related for using Polonius in the borrow checkerIssues related for using Polonius in the borrow checkerT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types 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.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Description
I'm filing this issue on behalf of @carlini, who discovered the initial unsoundness reproducer with an LLM. I then minimized the code to the code below.
The code below creates a &mut that aliases with a &, and somehow uses both of them, causing unsoundness. The aliasing references are r and p.
#![forbid(unsafe_code)]
type Payload = Option<Box<i32>>;
type P<'a, 'b> = for<'x> fn(&'a mut &'b Payload, &'x ()) -> &'x Payload;
fn f<'a, 'b, 'c>(x: &'a mut &'b Payload, _: &'c ()) -> &'b Payload {
*x
}
fn main() {
let p: &'static mut Payload = Box::leak(Box::new(Some(Box::new(1))));
let mid: &mut &Payload = Box::leak(Box::new(&*p));
let r: &Payload = (f as P<'_, '_>)(mid, &());
let b: &Box<i32> = r.as_ref().unwrap();
if false {
let _: &mut &'static Payload = mid;
} else {
*p = None;
println!("{b}"); // Segfault
};
}The unsoundness reproduces with -Zpolonius=next, but doesn't reproduce (fails to compile) with -Zpolonius=no.
Meta
Reproducible on the playground with version 1.100.0-nightly (2026-08-20 8925ea358a0f265ca610)
Reacted by kamulos
Metadata
Metadata
Assignees
Labels
A-borrow-checkerArea: The borrow checkerArea: The borrow checkerA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)C-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessNLL-poloniusIssues related for using Polonius in the borrow checkerIssues related for using Polonius in the borrow checkerT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types 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.This issue requires a nightly compiler in some way. When possible, use a F-* label instead.
Activity
lcnr commentedon Aug 25, 2026
let r: &Payload = (f as P<'_, '_>)(mid, &());seems like it's very much related to #25860. Unsure what causes polonius to behave worse hereamandasystems commentedon Sep 16, 2026
I've looked into this some (and will look into it more) and I think the reason for the difference here is a placeholder outlives constraint which increases the lifetime in NLL, but for some reason doesn't in Polonius.