This is an archive of the discontinued LLVM Phabricator instance.

[clang][dataflow] Fix crash when RHS of `&&` or `||` calls `noreturn` func.
ClosedPublic

Authored by mboehme on Mar 21 2023, 4:30 AM.

Details

Summary

The crash happened because the transfer fucntion for && and ||
unconditionally tried to retrieve the value of the RHS. However, if the RHS
is unreachable, there is no environment for it, and trying to retrieve the
operand's value causes an assertion failure.

See also the comments in the code for further details.

Diff Detail

Event Timeline

mboehme created this revision.Mar 21 2023, 4:30 AM
Herald added a project: Restricted Project. · View Herald Transcript
mboehme requested review of this revision.Mar 21 2023, 4:30 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 21 2023, 4:30 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
gribozavr2 accepted this revision.Mar 21 2023, 4:33 AM
gribozavr2 added a subscriber: gribozavr2.
gribozavr2 added inline comments.
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
399

getValueForDecl?

A value corresponds to a decl, a value for the decl.

"From" suggests that the value is inside the decl, or that we transform the decl into a value.

This revision is now accepted and ready to land.Mar 21 2023, 4:33 AM
sgatev accepted this revision.Mar 21 2023, 4:43 AM
sgatev added inline comments.
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
52

What do you think about making this a const reference? Alternatively, let's document that it must not be null?

mboehme updated this revision to Diff 506917.Mar 21 2023, 4:45 AM

Changes in response to review comments.

mboehme marked an inline comment as done.Mar 21 2023, 4:46 AM
mboehme added inline comments.
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
399

Good point -- done!

mboehme updated this revision to Diff 506919.Mar 21 2023, 4:50 AM
mboehme marked an inline comment as done.

Changes in response to review comments.

mboehme marked an inline comment as done.Mar 21 2023, 4:51 AM
mboehme added inline comments.
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
52

Good point -- done!

mboehme marked an inline comment as done.Mar 21 2023, 4:51 AM
ymandel accepted this revision.Mar 21 2023, 5:40 AM

Nice! Thank you.

clang/lib/Analysis/FlowSensitive/Transfer.cpp
174–175

nit. reworded (using A => B => C is the same as A & B => C). but, your call.

This fix looks good for me for this particular problem, but I wonder whether the solution is general enough. In case the analysis figures out that a call would not return (e.g., the value method is called on a provably empty optional, and it would throw instead of returning), would this approach still work? Would the analysis update the BlockReachable bitvector on demand?

This fix looks good for me for this particular problem, but I wonder whether the solution is general enough. In case the analysis figures out that a call would not return (e.g., the value method is called on a provably empty optional, and it would throw instead of returning), would this approach still work? Would the analysis update the BlockReachable bitvector on demand?

No, I think this is a different case.

BlockReachable is intended to encode reachability solely as defined by the structure of the CFG. The whole problem we're trying to solve in this patch is that the CFG understands that noreturn functions don't return and therefore eliminates any successor edges from calls to noreturn functions. This means that some of the CFG nodes become unreachable; specifically, in our case, the RHS of the && and || become unreachable, and so the dataflow analysis never computes a value for them. We therefore need to make sure that we don't try to query the value of the RHS in this case.

The case of calling value on a provably empty optional is different: The CFG does not understand that such a call does not return and therefore generates successor edges as it would for any other function call.

A side effect of the logic that this patch adds is that we get some neat inference results, as demonstrated in the newly added test. However, generating these results isn't the main goal of this patch; the patch is merely intended to ensure that we can process CFGs containing unreachable nodes caused by noreturn functions.

It would certainly be nice to generate similar inference results in the example that you mention (value on a provably empty optional), but that would require more work and a different approach.

mboehme updated this revision to Diff 507287.Mar 22 2023, 2:56 AM

Reworded comment.

mboehme updated this revision to Diff 507288.Mar 22 2023, 2:57 AM

Reworded comment again.

mboehme marked an inline comment as done.Mar 22 2023, 2:58 AM
mboehme added inline comments.
clang/lib/Analysis/FlowSensitive/Transfer.cpp
174–175

Thanks, this is easier to understand. Done!

xazax.hun added a comment.EditedMar 22 2023, 8:29 AM

No, I think this is a different case.

Sorry, I might have been unclear. I 100% agree that these are different cases. I was wondering whether we can/should have a single code path supporting both. But I do not insist since we do not seem to have precedent for the scenario I mentioned and do not want to block anything based on hypotheticals.

xazax.hun accepted this revision.Mar 22 2023, 8:31 AM
mboehme marked an inline comment as done.Mar 23 2023, 12:36 AM

No, I think this is a different case.

Sorry, I might have been unclear. I 100% agree that these are different cases. I was wondering whether we can/should have a single code path supporting both. But I do not insist since we do not seem to have precedent for the scenario I mentioned and do not want to block anything based on hypotheticals.

Got it, thanks!