-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add details about how significant drop in match scrutinees can cause deadlocks #8981
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
Add details about how significant drop in match scrutinees can cause deadlocks #8981
Conversation
r? @Alexendoo (rust-highfive has picked a reviewer for you, use r? to override) |
@oli-obk Apologies for the delay, but I have added more details about the lint, linked to documentation generated as part of clippy, and tried to make the lifetime of the temporary clearer. I believe you mentioned including wg-diagnostics on the code review. Is that a group I can @ here or do I need to send a link to the PR somewhere? Thank you! |
match, so side effects from dropping such temporaries are delayed. \ | ||
Deadlocks can occur if a lock guard is created in the scrutinee and a new \ | ||
lock guard for the same mutex is created in a match arm. \ | ||
For more information, see https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee"); |
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.
This link is automatically added to every clippy lint, unless explicitly disabled through an undocumented env var. So no need to add it here.
I don't think adding such a big paragraph to a lint message is what was suggested. We don't add full lint explanations to lint messages, that's what the lint documentation is for. I can't think of a rustc or Clippy lint where something like this is done. Can you link the discussion where adding this was suggested?
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.
@flip1995 Thank you for the review! It looks like I might have misunderstood Oli's suggestion here: rust-lang/rust#93883 (comment)
Particularly this part:
the diagnostic messaging needs to explain why this is a problem, ideally with some links to documentation and examples
maybe even add a short span pointing to the end of the match stating that the lock holds until there, so if any arms directly or via function calls lock again, you're in a deadlock
I've tried to make the messages smaller, but I did see one PR opened in another project due to this lint where it was mentioned that the current output was unhelpful and confusing. If you think this is still too much, I will keep trying to trim it down.
I had another question actually -- I was able to point to the end of the match, but it's cutting out the middle of the block, and I think the lack of context is going to be confusing. How can I keep the full match block, or at least a few of the last lines?
This link is automatically added to every clippy lint, unless explicitly disabled through an undocumented env var. So no need to add it here.
Oh, I completely missed this! Thank you! The URL has been removed as well.
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.
Ah yeah, we might want to improve the messaging a bit. But just writing a big paragraph won't help here. I think the ideal thing to do would be something like:
error: temporary with drop impl with side effects in match scrutinee lives to end of block
--> $DIR/significant_drop_in_scrutinee.rs:59:11
|
LL | match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | 42 => mutex.lock().unwrap().bar()
| ^^^^^^^^^^^^ note: new side effect temporary created here
...
LL | };
| - original temporary lives until here
|
= note: this might lead to deadlocks or other unexpected behavior
help: try moving the temporary above the match
|
LL ~ let value = mutex.lock().unwrap().foo();
LL ~ match value {
|
But this would entail, that we also try to find other significant drop temporaries inside the match block, which might be a bit hard. A first step might be to find any significant drop temp inside the match and point to it. The next step would be to compare if it comes from the same root (i.e. same mutex), which might be way harder.
You only have to include wg-diag once this lint gets on the way to be uplifted. Until then all reviews are done by the Clippy team. |
LL | match counter.temp_increment().len() { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
... | ||
LL | }; | ||
| - temporary lives until here. If mutex is locked within block, deadlocks can occur. |
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.
The message could be confusing when there's no mutexes involved. It would be good to be able to say
if
counter
is a mutex that is locked within the block, deadlocks can occur
Or something to those effects, if getting the name is tricky
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.
Agreed. See my above suggestion #8981 (comment) Don't mention mutexes at all, but say what the result might be. Which is "deadlocks or other unexpected behavior".
74f42ae
to
a97fe06
Compare
@flip1995 @Alexendoo The new commit will look for any type in the arms that has a significant drop -- this is not 100% correct, since it's possible that a different "parent" is creating the new temporary. All the types found in the arms are indicated with notes and a final note is added with the message |
Adds more details about how a significant drop in a match scrutinee can cause a deadlock and include link to documentation. Emits messages indicating temporaries with significant drops in arms of matches and message about possible deadlocks/unexpected behavior. changelog: Add more details to significant drop lint to explicitly show how temporaries in match scrutinees can cause deadlocks/unexpected behavior.
68ec83a
to
2476100
Compare
I also had some issues after trying to rebase and ended up force pushing an entirely new squashed commit. I hope I haven't made re-reviewing too annoying for you. |
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.
I would say: don't overthink it. The current version is definitely good enough. Bringing MIR into this lint would make it way too complicated and pretty unmaintainable. I have a few suggestions on how to improve the wording of the lint a little further.
I'm a little concerned about the perf impact of checking every arm of a match. Clippy has pretty big match blocks, so I should be able to time this change on Clippy itself.
for span in spans { | ||
diag.span_label(span, "significant drop in arm here"); | ||
} | ||
diag.note("this might lead to deadlocks or other unexpected behavior"); |
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.
I would add this note unconditionally.
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.
Done!
help: try moving the temporary above the match | ||
| | ||
LL ~ let value = mutex1.lock().unwrap().s.len(); | ||
LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | ||
| | ||
|
||
error: temporary with significant drop in match scrutinee | ||
error: temporary with drop impl with side effects in match scrutinee lives to end of block |
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.
error: temporary with drop impl with side effects in match scrutinee lives to end of block | |
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression |
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.
Done!
| | ||
... | ||
LL | mutex1.lock().unwrap().s.len(); | ||
| ---------------------- significant drop in arm here |
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.
| ---------------------- significant drop in arm here | |
| ---------------------- another temporary with significant `Drop` created here |
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.
Oh, good call, because this could be in a for-loop as well
@flip1995 Thank you for the comments! My initial assumption was that checking all the arms wouldn't add a lot of overhead because it would only happen when a significant drop was found in the match scrutinee/for-loop condition, but having evidence one way or the other would be great. |
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.
Since it's only run when a candidate is found as you say, the extra visitor should be fine performance wise
When #[allow(clippy::significant_drop_in_scrutinee)]
is used it seems the and_then
callback isn't triggered which would mean no problem there either. It is called for #[expect]
however (cc @xFrednet in case that's a bug)
If you wanted to err on the side of caution you could throw an is_lint_allowed
at the top of check
, that would allow skipping the initial significant drop checking too
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.
Thanks! This all LGTM now. I still want to benchmark it though.
Lints should process as usual, if the lint is expected. It sounds like this behaves how it should. Thank you for pinging me 🙃 |
Thanks everyone for your help! |
We don't need "real" benchmark numbers. It would be enough if you run |
Nvm, I just did that myself. I didn't see any significant changes. Thanks for continuing improving this already awesome lint. Let's get this merged so people can test it in nightly on Friday @bors r+ |
📌 Commit 7bc4096 has been approved by |
@flip1995 My apologies for the delay in responding! I just saw this. Thank you for running the benchmarks and for helping me get this far! |
No need to apologies. My two messages were in the span of 15 minutes :D |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Adds more details about how a significant drop in a match scrutinee can cause a deadlock and include link to documentation.
changelog: Add more details to significant drop lint to explicitly show how temporaries in match scrutinees can cause deadlocks.