-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
[analyzer] Fix StdLibraryFunctionsChecker crash on surprising sink node #66109
[analyzer] Fix StdLibraryFunctionsChecker crash on surprising sink node #66109
Conversation
@llvm/pr-subscribers-clang ChangesRecent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags. In the unlikely case when the updated state (the variable However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the This commit introduces an explicit This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.Full diff: https://github.com/llvm/llvm-project/pull/66109.diff 1 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index f5f6e3a91237686..d3a41dd9aff2891 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -1387,8 +1387,8 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, if (!NewState) continue; - // It is possible that NewState == State is true. - // It can occur if another checker has applied the state before us. + // Here it's possible that NewState == State, e.g. when other checkers + // already applied the same constraints (or stricter ones). // Still add these note tags, the other checker should add only its // specialized note tags. These general note tags are handled always by // StdLibraryFunctionsChecker. @@ -1427,8 +1427,13 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, }); Pred = C.addTransition(NewState, Pred, Tag); } - if (!Pred) + if (!Pred || Pred->isSink()) { + // Pred may be: + // - a nullpointer, when the generated node is not new; + // - a sink, when NewState is posteriorly overconstrained. + // In these situations we cannot add the errno note tag. continue; + } } // If we can get a note tag for the errno change, add this additionally to |
@llvm/pr-subscribers-clang-static-analyzer-1 ChangesRecent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags. In the unlikely case when the updated state (the variable However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the This commit introduces an explicit This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.Full diff: https://github.com/llvm/llvm-project/pull/66109.diff 1 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index f5f6e3a91237686..d3a41dd9aff2891 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -1387,8 +1387,8 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, if (!NewState) continue; - // It is possible that NewState == State is true. - // It can occur if another checker has applied the state before us. + // Here it's possible that NewState == State, e.g. when other checkers + // already applied the same constraints (or stricter ones). // Still add these note tags, the other checker should add only its // specialized note tags. These general note tags are handled always by // StdLibraryFunctionsChecker. @@ -1427,8 +1427,13 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, }); Pred = C.addTransition(NewState, Pred, Tag); } - if (!Pred) + if (!Pred || Pred->isSink()) { + // Pred may be: + // - a nullpointer, when the generated node is not new; + // - a sink, when NewState is posteriorly overconstrained. + // In these situations we cannot add the errno note tag. continue; + } } // If we can get a note tag for the errno change, add this additionally to |
clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Outdated
Show resolved
Hide resolved
Recent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags. In the unlikely case when the updated state (the variable `NewState`) was posteriorly overconstrained, the engine marked the node after the first state transition as a sink to stop the "natural" graph exploration after that point. However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the `addPredecessor()` method of `ExplodedNode`. This commit introduces an explicit `isSink()` check to avoid this crash. To avoid similar bugs in the future, perhaps it would be possible to tweak `addTransition()` and ensure that it returns `nullptr` when it would return a sink node (to unify the two possible error conditions). This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.
48deb9b
to
b5c4590
Compare
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 don't think it deserves a fragile test case.
I think the fix looks good.
I also agree with your other statements on the addTransition subject.
…de (llvm#66109) Recent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags. In the unlikely case when the updated state (the variable `NewState`) was posteriorly overconstrained, the engine marked the node after the first state transition as a sink to stop the "natural" graph exploration after that point. However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the `addPredecessor()` method of `ExplodedNode`. This commit introduces an explicit `isSink()` check to avoid this crash. To avoid similar bugs in the future, perhaps it would be possible to tweak `addTransition()` and ensure that it returns `nullptr` when it would return a sink node (to unify the two possible error conditions). This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.
…de (llvm#66109) Recent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags. In the unlikely case when the updated state (the variable `NewState`) was posteriorly overconstrained, the engine marked the node after the first state transition as a sink to stop the "natural" graph exploration after that point. However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the `addPredecessor()` method of `ExplodedNode`. This commit introduces an explicit `isSink()` check to avoid this crash. To avoid similar bugs in the future, perhaps it would be possible to tweak `addTransition()` and ensure that it returns `nullptr` when it would return a sink node (to unify the two possible error conditions). This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.
Local branch amd-gfx 737eb03 Merged main:602e47c5f9fd into amd-gfx:f337c8eadcf3 Remote branch main 0b2778d [analyzer] Fix StdLibraryFunctionsChecker crash on surprising sink node (llvm#66109)
Recent changes in StdLibraryFunctionsChecker introduced a situation where the checker sequentially performed two state transitions to add two separate note tags.
In the unlikely case when the updated state (the variable
NewState
) was posteriorly overconstrained, the engine marked the node after the first state transition as a sink to stop the "natural" graph exploration after that point.However, in this particular case the checker tried to directly add a second node, and this triggered an assertion in the
addPredecessor()
method ofExplodedNode
.This commit introduces an explicit
isSink()
check to avoid this crash. To avoid similar bugs in the future, perhaps it would be possible to tweakaddTransition()
and ensure that it returnsnullptr
when it would return a sink node (to unify the two possible error conditions).This crash was observed in an analysis of the curl project (in a very long and complex function), and there I validated that this is the root cause, but I don't have a self-contained testcase that can trigger the creation of a PosteriorlyOverconstrained node in this situation.