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

Don't hit thread-local-storage when entering catch_unwind #34787

Closed
alexcrichton opened this issue Jul 12, 2016 · 12 comments
Closed

Don't hit thread-local-storage when entering catch_unwind #34787

alexcrichton opened this issue Jul 12, 2016 · 12 comments
Labels
E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-slow Issue: Problems and improvements with respect to performance of generated code.

Comments

@alexcrichton
Copy link
Member

Although TLS is fast, it's not that fast on Windows and we shouldn't be hitting it on the fast path for catch_unwind. Right now all we do this for is to reset the panic counter back to 0.

The purpose of this is to allow code like this to work, but thinking more about that I believe that's actually undefined behavior on MSVC. Basically once a panic is initiated you can't initiate another panic for... "reasons". (I'm not 100% clear myself). This definitely seems like a sketchy pattern as well!

So if we don't want to enable that pattern, I think we can get away with different management of the panic counter:

  • When a panic starts, bump the panic counter. If this indicates a double panic, abort.
  • When a catch_unwind returns from catching a panic, decrease the panic counter. (maybe assert it's 0?)

This way the normal usage of catch_unwind where nothing panics should never hit TLS, and we should still be able to use panics as we do today.

@alexcrichton alexcrichton added A-libs I-slow Issue: Problems and improvements with respect to performance of generated code. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Jul 12, 2016
@alexcrichton
Copy link
Member Author

Although not an easy bug to dive into, this shouldn't be too hard to do so. I'd totally be willing to mentor anyone who'd like to tackle this!

@nikhilshagri
Copy link
Contributor

nikhilshagri commented Jul 12, 2016

I would like to work on this! I still have a few days before my college starts, so I sure can spend some time working on a not-so-easy bug! 😀

@alexcrichton
Copy link
Member Author

@cynicaldevil go for it! If you need any help let me know, and to clarify the TLS access I'm thinking about is this one right here. I believe we only need to hit TLS once we catch an actual panic, not when we enter or if we leave without catching a panic.

@nikhilshagri
Copy link
Contributor

nikhilshagri commented Jul 12, 2016

@alexcrichton Since a panic cannot be started when one's already active, the panic counter can only have two values(0 and 1). Therefore, wouldn't it be better to keep track of this using a bool?

@alexcrichton
Copy link
Member Author

Nah I think we'll need to keep a counter because on a double panic I believe we still invoke the panic hook, and if that panics then the counter will be at 2. The value of 2 is understood as "don't even run the panic hook, just get out of here ASAP"

@nikhilshagri
Copy link
Contributor

@alexcrichton Oh, alright then!

@nikhilshagri
Copy link
Contributor

@alexcrichton Ok, here's what I got after scanning the source code:

  • We only need to hit TLS if there's a panic, so the code for checking whether a panic has occurred (this code here) can be moved out of the closure.
  • If, and only if we get a panic, we access TLS and decrement the PANIC_COUNT by one, and then return the Err.

Is this correct?

@nagisa
Copy link
Member

nagisa commented Jul 14, 2016

Basically once a panic is initiated you can't initiate another panic for... "reasons". (I'm not 100% clear myself). This definitely seems like a sketchy pattern as well!

That’s a well known pattern called rethrowing.

If, and only if we get a panic, we access TLS and decrement the PANIC_COUNT by one, and then return the Err.

You also should check that PANIC_COUNT is 0 after decrement in this case, as otherwise you’re either double-panicking or there’s a bug (underflow). While, I believe, the panic!() should handle the double-panic just fine even inside the catch_panic, I feel like it will not properly handle a bug where panicking did not increment PANIC_COUNT for some reason.

@alexcrichton
Copy link
Member Author

@cynicaldevil

Yes I believe that's correct. I think it should be ok to add this at the end of the function (for both the success and happy paths):

debug_assert!(PANIC_COUNT.with(|c| c.get()), 0);

@nagisa

That’s a well known pattern called rethrowing.

Unfortunately this is actually entirely different in how you'd be supposed to codegen it. Thinking more on this now, I've been informed that if you're in a cleanup pad then it's undefined behavior to raise another exception on MSVC. I believe on Unix it's fine, however.

I also believe that rethrowing is implemented by actually catching an exception and then calling library functions to rethrow it. In LLVM a catch pad is quite different from a cleanup pad (which we generate everywhere).

@nikhilshagri
Copy link
Contributor

@alexcrichton If we were to add that statement, then TLS would be accessed anyway, regardless of whether there was a panic or not, which is what we are trying to avoid. I think it must only be added for the path in which a panic occurs.

@nagisa
Copy link
Member

nagisa commented Jul 15, 2016

Yes, that's correct there's no point in checking that in the panic-less
case.

On Jul 15, 2016 13:42, "Nikhil Shagrithaya" notifications@github.com
wrote:

@alexcrichton https://github.com/alexcrichton If we were to add that
statement, then TLS would be accessed anyway, regardless of whether there
was a panic or not, which is what we are trying to avoid. I think it must
only be added for the path in which a panic occurs.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#34787 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AApc0kXLSpN-5qLX7V9zMJ5upDGxFM7uks5qV2QggaJpZM4JKpT0
.

@alexcrichton
Copy link
Member Author

@cynicaldevil ah yeah sure in debug mode it'll hit TLS, but it'll get optimized away in release mode and it's a good sanity check in theory (not required though)

@arielb1 arielb1 reopened this Jul 16, 2016
Manishearth added a commit to Manishearth/rust that referenced this issue Jul 17, 2016
…richton

Refactored code to access TLS only in case of panic (II)

Fixes rust-lang#34787
r? @alexcrichton
Do it **very** carefully this time!
bors added a commit that referenced this issue Aug 11, 2016
Refactored code to access TLS only in case of panic (II)

Fixes #34787
r? @alexcrichton
Do it **very** carefully this time!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-slow Issue: Problems and improvements with respect to performance of generated code.
Projects
None yet
Development

No branches or pull requests

4 participants