Skip to content
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

sync::Once and panicking closure #31688

Closed
ghost opened this issue Feb 15, 2016 · 10 comments
Closed

sync::Once and panicking closure #31688

ghost opened this issue Feb 15, 2016 · 10 comments
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@ghost
Copy link

ghost commented Feb 15, 2016

The documentation for sync::Once does not clarify what happens if given closure
panics. Currently I would rather expect that call_once will execute the closure
only once, whether it panics or not. But this is not what happens:

#![feature(recover)]

use std::sync::*;
use std::panic::recover;

static ONCE : Once = ONCE_INIT;

fn main() {
    for i in 1..10 {
        let _ = recover(|| { 
            ONCE.call_once(|| {
                let s = if i > 1 { "s" } else { ""};
                panic!("Once::call_once called {} time{}", i, s);
            }); 
        });
    }
}

Prints:

thread '<main>' panicked at 'Once::call_once called 1 time', <anon>:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
thread '<main>' panicked at 'Once::call_once called 2 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 3 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 4 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 5 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 6 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 7 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 8 times', <anon>:13
thread '<main>' panicked at 'Once::call_once called 9 times', <anon>:13

Either way documentation needs a slight improvement. And additionally code if
it is not a desired behaviour. As a side comment I will note that this
behaviour differs between languages. In C++ for example std::call_once to
proceed must not exit via exception, in Go on the other hand exiting via panic
counts as successful execution.

@alexcrichton
Copy link
Member

triage: I-nominated

@alexcrichton alexcrichton added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Feb 16, 2016
@alexcrichton
Copy link
Member

I don't really have an opinion on what the semantics should be in this case, but I'm curious what others think!

@sfackler
Copy link
Member

I personally think the current behavior is fine (a common use case for Once it to initialize something, and if the closure panics it probably hasn't been initialized), but we should document it.

@bluss
Copy link
Member

bluss commented Feb 16, 2016

panic inside call_once is a very broken scenario.

Maybe it would only help authors of critical unsafe code if we ensured the closure could only be called once ever. The closure call could be enforced to abort on panic (it should be a "noexcept" zone).

It's an FnOnce closure, so being called twice is an unsoundness problem, too. (See below)

@bluss
Copy link
Member

bluss commented Feb 16, 2016

Interesting, it's not broken because of FnOnce, the actual closure value is only called once (or never).

@aturon
Copy link
Member

aturon commented Feb 18, 2016

cc me

@brson
Copy link
Contributor

brson commented Feb 18, 2016

I prefer poisoning it, without any options to unpoison. Alternately, just leaving it alone.

@alexcrichton
Copy link
Member

The libs team discussed this during triage yesterday and we didn't necessarily reach any concrete conclusion. As @brson mentioned we talked about how we may want to just poison a Once in the same way mutexes and rwlocks are poisoned, but it also seemed that if we didn't do that the behavior here was reasonable.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 25, 2016
This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of rust-lang#31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes rust-lang#31688
Manishearth added a commit to Manishearth/rust that referenced this issue Mar 26, 2016
std: Rewrite Once with poisoning

This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of rust-lang#31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes rust-lang#31688
alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 26, 2016
This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of rust-lang#31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes rust-lang#31688
bors added a commit that referenced this issue Mar 26, 2016
std: Rewrite Once with poisoning

This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of #31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes #31688
@durka
Copy link
Contributor

durka commented May 11, 2016

This is marked as the tracking issue for the once_poison feature. Therefore, it should be reopened or a new tracking issue created.

@alexcrichton
Copy link
Member

Ah it's probably best to open a new tracking issue, would you be interested in doing so @durka?

durka added a commit to durka/rust that referenced this issue May 21, 2016
The tracking issue for once_poison was noted as rust-lang#31688 which was closed, so it now points to the new rust-lang#33577.
Manishearth added a commit to Manishearth/rust that referenced this issue May 21, 2016
update tracking issue for once_poison

The tracking issue for once_poison was noted as rust-lang#31688 which was closed, so it now points to the new rust-lang#33577.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants