This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Indicate if a parent state is infeasible
ClosedPublic

Authored by martong on Apr 29 2022, 8:15 AM.

Details

Summary

In some cases a parent State is already infeasible, but we recognize
this only if an additonal constraint is added. This patch is the first
of a series to address this issue. In this patch assumeDual is changed
to clone the parent State but with an Infeasible flag set, and this
infeasible-parent is returned both for the true and false case. Then
when we add a new transition in the exploded graph and the destination
is marked as infeasible, the node will be a sink node.

Related bug:
https://github.com/llvm/llvm-project/issues/50883
Actually, this patch does not solve that bug in the solver, rather with
this patch we can handle the general parent-infeasible cases.

Next step would be to change the State API and require all checkers to
use the assume*Dual API and deprecate the simple assume calls.

Hopefully, the next patch will introduce assumeInBoundDual and will
solve the CRASH we have here:
https://github.com/llvm/llvm-project/issues/54272

Diff Detail

Event Timeline

martong created this revision.Apr 29 2022, 8:15 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 8:15 AM
martong requested review of this revision.Apr 29 2022, 8:15 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 8:15 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
martong added inline comments.Apr 29 2022, 8:21 AM
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
96–97

This statement is false because our constraint solver is not precise.

Finally, we have this!

Can we have this https://godbolt.org/z/oferc6P5Y in addition to the one you proposed?
I find it more readable.

What performance hit will we suffer from this change?
Please do a differential analysis.

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
93–96

I would leave a note here that these two states might be equal in a very rare case (*); but one should not depend on that.

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
293–295
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
88

For the record, back then we had such flag. IDK when did we remove it, but we had it for sure.

148–150

These should not be public. Make friends if required.

clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
51

Should we mark this LLVM_UNLIKELY(cond)?
I would expect this function to be quite hot, and infeasible states rare.

Could we measure this one?

52–54

Add here some comments on why we return (Infeasible,Infeasible).
I would rather see StInfeasible to better discriminate what we are talking about. We already use StTrue and StFalse in this context though.

clang/test/Analysis/sink-infeasible.c
37–48 ↗(On Diff #426061)

You could use a non-default check prefix.

martong updated this revision to Diff 426635.May 3 2022, 3:52 AM
martong marked 6 inline comments as done.
  • Update according to review comments
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
51

Yes, it could be.

Let me come back with some measurement results soon. I am going to use llvm statistics macros to measure this, but that makes sense on top of D124758

clang/test/Analysis/sink-infeasible.c
37–48 ↗(On Diff #426061)

No I can't, because this test code in the comment is meaningful only in the baseline, I cannot run both clang versions from lit.

So, actually there is no RUN line for these, it is here only to demonstrate what happens in the baseline.

Finally, we have this!

Thanks for the review.

Can we have this https://godbolt.org/z/oferc6P5Y in addition to the one you proposed?
I find it more readable.

Sure, I find it also more readable. I will update soon.

What performance hit will we suffer from this change?
Please do a differential analysis.

I am doing that with the dependent patch https://reviews.llvm.org/D124758

I think I don't have anything left.
Let's see the numbers.

clang/test/Analysis/sink-infeasible.c
37–48 ↗(On Diff #426061)

Okay, why don't we drop these if these are only applicable to the baseline?
Should we really introduce 'stale' comments?

martong updated this revision to Diff 426715.May 3 2022, 8:11 AM
  • Add a simpler test case
martong added inline comments.May 3 2022, 8:27 AM
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
51

This is what I use for the measurement, stay tuned for the results.

diff --git a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
index ef98ed7d36e9..82097d67ec0f 100644
--- a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -16,10 +16,16 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/Statistic.h"

 using namespace clang;
 using namespace ento;

+#define DEBUG_TYPE "CoreEngine"
+
+STATISTIC(NumInfeasible, "The # of infeasible states");
+STATISTIC(NumFeasible, "The # of feasible states");
+
 ConstraintManager::~ConstraintManager() = default;

 static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
@@ -51,16 +57,20 @@ ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) {
     if (!StFalse) { // both infeasible
       ProgramStateRef Infeasible = State->cloneAsInfeasible();
       assert(Infeasible->isInfeasible());
+      ++NumInfeasible;
       return ProgramStatePair(Infeasible, Infeasible);
     }
+    ++NumFeasible;
     return ProgramStatePair(nullptr, StFalse);
   }

   ProgramStateRef StFalse = assumeInternal(State, Cond, false);
   if (!StFalse) {
+    ++NumFeasible;
     return ProgramStatePair(StTrue, nullptr);
   }

+  ++NumFeasible;
   return ProgramStatePair(StTrue, StFalse);
 }
martong marked an inline comment as done.May 3 2022, 8:30 AM
martong added inline comments.
clang/test/Analysis/sink-infeasible.c
37–48 ↗(On Diff #426061)

Ok, I can remove them if you insist, but I thought it might make it easier to understand what is changed.

martong marked an inline comment as done.May 3 2022, 8:36 AM
martong added inline comments.
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
51

Ups, the purpose of the measure is to determine if UNLIKELY is justified, so this diff seems better, restarted the measurement with it.

--- a/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -16,10 +16,16 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/Statistic.h"

 using namespace clang;
 using namespace ento;

+#define DEBUG_TYPE "CoreEngine"
+
+STATISTIC(NumInfeasible, "The # of infeasible states");
+STATISTIC(NumFeasible, "The # of feasible states");
+
 ConstraintManager::~ConstraintManager() = default;

 static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
@@ -51,8 +57,10 @@ ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) {
     if (!StFalse) { // both infeasible
       ProgramStateRef Infeasible = State->cloneAsInfeasible();
       assert(Infeasible->isInfeasible());
+      ++NumInfeasible;
       return ProgramStatePair(Infeasible, Infeasible);
     }
+    ++NumFeasible;
     return ProgramStatePair(nullptr, StFalse);
   }
martong added inline comments.May 3 2022, 10:47 AM
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
51

This is indeed UNLIKELY. Seems like a good upper-bound for the ratio's order of magnitude is around 1000 / 10 million i.e. 0.0001.

martong updated this revision to Diff 426785.May 3 2022, 11:14 AM
  • Add LLVM_UNLIKELY
steakhal accepted this revision.May 3 2022, 11:15 AM
This revision is now accepted and ready to land.May 3 2022, 11:15 AM

@NoQ Could you please take a look? This change effects the very core of the analyzer.

NoQ added a comment.May 4 2022, 10:41 AM

Yes, we've discussed this before, and I'm very much in favor of this change. This is assertion removal, and the assertion has been really useful back in the day, but the assertion doesn't seem to be realistic to maintain with all the new logic in the constraint solver coming in in recent years.

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
88

The reader deserves a massive amount of explanation here. Normally infeasible states are just null states. We need to explain how these new infeasible states are different.

Maybe a longer name? IsPostOverconstrained or something like that.

martong marked an inline comment as done.May 6 2022, 3:58 AM

Yes, we've discussed this before, and I'm very much in favor of this change. This is assertion removal, and the assertion has been really useful back in the day, but the assertion doesn't seem to be realistic to maintain with all the new logic in the constraint solver coming in in recent years.

Thanks for your review and support!

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
88

Okay, I've added an essay that explains these differences.

Maybe a longer name? IsPostOverconstrained or something like that.

Yeah, I agree a longer name could reflect that this is something that requires special handling. I chose PosteriorlyOverconstrained.

martong updated this revision to Diff 427594.May 6 2022, 3:58 AM
martong marked an inline comment as done.
  • Add explanatory comment, rename to PosteriorlyOverconstrained
steakhal accepted this revision.May 6 2022, 5:05 AM

only a few typos

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
89–114
martong added inline comments.May 6 2022, 5:54 AM
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
99

Yeah, thx, I've also found one more typo. That's the problem with long comments :D

martong updated this revision to Diff 427625.May 6 2022, 6:54 AM
martong marked 2 inline comments as done.
  • Fix typos in essay
This revision was automatically updated to reflect the committed changes.
thakis added a subscriber: thakis.May 10 2022, 2:07 AM

One of your 3 commits in https://github.com/llvm/llvm-project/compare/3d888b0491f8...34ac048aef29 broke check-clang on Windows: http://45.33.8.238/win/57870/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

martong added inline comments.May 12 2022, 1:01 AM
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
46

TODO We should have a very similar implementation for assumeInclusiveRangeDual! (Not that high prio, that is used only by the BoolAssignmentChecker).

This comment was removed by mehdi_amini.
This comment was removed by mehdi_amini.