Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upThread cancellation, asynchronous unwinding exceptions and their interaction with drops #46
Comments
nagisa
changed the title
Thread cancellation, unwinding and their interaction with drops
Thread cancellation, asynchronous unwinding exceptions and their interaction with drops
Mar 29, 2018
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Mar 29, 2018
|
To be clear, Windows has a Forking a multi-threaded process also results in something which strongly resembles killing a thread: the child process after forking will only have a single thread, effectively making it look like all other threads have been killed. This has the same downsides as Since both forking and |
This comment has been minimized.
This comment has been minimized.
|
According to the documentation of TerminateThread "the system frees
thread's initial stack" which is exactly what constitutes a violation of
"must not remove before drop" and was decided to be unsound. If the thread
stack was leaked, such function would have been fineish to use from the
soundness perspective.
|
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Mar 29, 2018
|
let mut var = 0;
crossbeam::scope(|scope| {
scope.spawn(|| loop { var += 1; } );
unsafe { pthread_exit(); }
});Using Note that this includes the standard library and any external crates that you might be using. The case for external crates is simple: you are responsible for auditing them (with no help from Rust's type system). However for the standard library this is a bit more complicated: do we want to stable-guarantee that all of the libstd code involved in spawning a thread (
Ah, I seem to have missed that. In that case |
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Mar 29, 2018
|
Asynchronous cancellation using
|
This comment has been minimized.
This comment has been minimized.
Plan is to have unwinding from FFI be fine if the functions are annotated with |
This comment has been minimized.
This comment has been minimized.
|
Also, thanks for writing down all these things. Most of those questions have been floated around during the All-hands, but I ended up not remembering any of them :) |
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Mar 29, 2018
|
Regarding However using |
This comment has been minimized.
This comment has been minimized.
|
@Amanieu |
This comment has been minimized.
This comment has been minimized.
|
I don't think trying to make So, these will have to be unsafe operations. In terms of when they (and also e.g. |
This comment has been minimized.
This comment has been minimized.
Oh no this cannot possibly work. If you unwind e.g. during the execution of |
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Mar 29, 2018
|
We know that none of these functions are safe. What we are trying to determine here is: under which conditions is using them (not) UB? Additionally, we are only look at this from the language point of view: everyone will agree that most Rust code assumes that panics don't come from arbitrary instructions and that destructors are executed while unwinding. If a user wants to do "fancy" stuff with unwinding (or the lack thereof) then he is solely responsible for auditing any code that he may be unwinding through to ensure that safety is maintained. |
This comment has been minimized.
This comment has been minimized.
Ack.
Right, we'll have to decide that. I said my 2 cents above. |
This comment has been minimized.
This comment has been minimized.
jugglerchris
commented
Apr 5, 2018
Could there could be some kind of annotation you could use to make this audit easier, at least locally? The compiler must know whether there are any fn may_longjmp() {
let foo = make_foo();
// Fail to compile if any destructors would run on unwind (here for foo)
#[no_drop_on_stack]
ffi_function_which_may_longjmp();
}You'd still need to annotate up your call stack to the point where |
nagisa commentedMar 29, 2018
So during the all-hands we identified a use-case that would be good to be documented in the unsafe code guidelines.
There are at least three sources of "cancellation" which might end up "removing" (in Taylor’s words) a value without "dropping" it, which in turn results in unsoundness for e.g. rayon, crossbeam, &pin stuff. These sources are:
longjmp/setjmp(used in practice for error handling by rust lua and perhaps many other embedded languages/interpreters);pthread_cancel: which can run either an asynchronous unwinding exception (might occur at any program point) or raise an unwindingexception at well specified points such assleep; exact behaviour is specified bypthread_setcancelstate.pthread_exit,pthread_kill: which will "stop" the thread, potentially executing some arbitrary code and cleaning the thread up (freeing thread’s stack).There’s no question that these functions may be useful in one scenario or the other, so it would be good if we figured out scenarios in which these functions are sound to use (e.g. if the thread stack contains only
Copytypes) and encoded this information into our unsafe code guidelines book.cc @nikomatsakis @cramertj