- 
        Couldn't load subscription status. 
- Fork 13.9k
scoped threads: pass closure through MaybeUninit to avoid invalid dangling references #102589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any  Examples of  
 | 
        
          
                library/std/src/thread/mod.rs
              
                Outdated
          
        
      There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, this has the side effect that if the closure is dropped before being run, we leak f. That is probably not what we want... bit right now that is hard to avoid. We'd need a small wrapper type around MaybeUninit that drops its contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the stdlib use scopeguard? Writing such ad-hoc drop glues becomes the breeze it should have always been:
let mb_dangling_f = ::scopeguard::guard(MaybeUninit::new(f), /* drop: */ |f| unsafe {
    drop(MaybeUninit::assume_init(f));
});
let closure = move/*(mb_dangling_f, ..)*/ |…| {
    let f = ScopeGuard::into_inner(mb_dangling_f);
    let f = unsafe {
        MaybeUninit::assume_init(f)
    };There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I don't think it does.
d3db1d4    to
    a0204bb      
    Compare
  
    a0204bb    to
    78b577c      
    Compare
  
    | @bors r+ | 
Rollup of 7 pull requests Successful merges: - rust-lang#102258 (Remove unused variable in float formatting.) - rust-lang#102277 (Consistently write `RwLock`) - rust-lang#102412 (Never panic in `thread::park` and `thread::park_timeout`) - rust-lang#102589 (scoped threads: pass closure through MaybeUninit to avoid invalid dangling references) - rust-lang#102625 (fix backtrace small typo) - rust-lang#102859 (Move lifetime resolution module to rustc_hir_analysis.) - rust-lang#102898 (rustdoc: remove unneeded `<div>` wrapper from sidebar DOM) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
| Just looking at this cause it was in twir and I'm confused - doesn't  | 
| The bug is described in a bit more detail at #101983, does that help? | 
The
mainfunction defined here looks roughly like this, if it were written as a more explicit stand-alone function:Note that
threadcontinues to run even aftersignal_done! Now consider what happens if theclosurecaptures a reference of lifetime'lifetime:closureis a struct (the implicit unnameable closure type) with a&'lifetime mut Tfield. References passed to a function are marked withdereferenceable, which is LLVM speak for this reference will remain live for the entire duration of this function.signal_doneruns. Then -- potentially -- this thread gets scheduled away and the main thread runs, seeing the signal and returning to the user. Now'lifetimeends and the memory the reference points to might be deallocated.threadwith the promise of remaining live for the entire duration of the function, actually got deallocated while the function still runs. Oops.Long-term I think we should be able to use
ManuallyDropto fix this withoutunsafe, or maybe a newMaybeDanglingtype. I am working on an RFC for that. But in the mean time it'd be nice to fix this so that Miri with-Zmiri-retag-fields(which is needed for "full enforcement" of all the LLVM flags we generate) stops erroring on scoped threads.Fixes #101983
r? @m-ou-se