ASDenysPetrov updated this revision to Diff 272997.
ASDenysPetrov added a comment.

@NoQ thanks for the approval. But I'm afraid we should return the check for 
`!V.getAs<nonloc::LazyCompoundVal>()` back in `CStringChecker::assumeZero`.

Look, I paid attention to the fix for https://llvm.org/PR24951 and related 
commit rG480a0c00ca51d909a925120737b71289cbb79eda 
<https://reviews.llvm.org/rG480a0c00ca51d909a925120737b71289cbb79eda>. I saw 
that @dcoughlin added a check for `V.getAs<nonloc::LazyCompoundVal>()` to fix 
and the old code used it implicitly. My patch returns this issue back. That's 
why we need to add the check for `LazyCompoundVal` as well.

Another big question is why `LazyCompoundVal` can be possible here at all. As I 
see according to the graph below the answer is somewhere deep in the core. Thus 
I'd propose to apply this patch in scope of fix https://llvm.org/PR37503.
F11723847: tmp63ucwe5i.html <https://reviews.llvm.org/F11723847>

I updated the patch. I've also added a //FIXME// caveat.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77062/new/

https://reviews.llvm.org/D77062

Files:
  clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  clang/test/Analysis/string.c

Index: clang/test/Analysis/string.c
===================================================================
--- clang/test/Analysis/string.c
+++ clang/test/Analysis/string.c
@@ -363,6 +363,14 @@
     strcpy(x, y); // no-warning
 }
 
+void *func_strcpy_no_assertion();
+char ***ptr_strcpy_no_assertion;
+void strcpy_no_assertion() {
+  *(unsigned char **)ptr_strcpy_no_assertion = (unsigned char *)(func_strcpy_no_assertion());
+  char c;
+  strcpy(**ptr_strcpy_no_assertion, &c); // no-assertion
+}
+
 //===----------------------------------------------------------------------===
 // stpcpy()
 //===----------------------------------------------------------------------===
Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -196,9 +196,8 @@
   void evalBzero(CheckerContext &C, const CallExpr *CE) const;
 
   // Utility methods
-  std::pair<ProgramStateRef , ProgramStateRef >
-  static assumeZero(CheckerContext &C,
-                    ProgramStateRef state, SVal V, QualType Ty);
+  std::pair<ProgramStateRef, ProgramStateRef> static assumeZero(
+      ProgramStateRef state, SVal V);
 
   static ProgramStateRef setCStringLength(ProgramStateRef state,
                                               const MemRegion *MR,
@@ -279,16 +278,18 @@
 // Individual checks and utility methods.
 //===----------------------------------------------------------------------===//
 
-std::pair<ProgramStateRef , ProgramStateRef >
-CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
-                           QualType Ty) {
+std::pair<ProgramStateRef, ProgramStateRef>
+CStringChecker::assumeZero(ProgramStateRef state, SVal V) {
+  auto states = std::make_pair(state, state);
+
   Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
-  if (!val)
-    return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
+  // FIXME: We should understand how LazyCompoundVal can be possible here,
+  // fix the root cause and get rid of this check.
+  if (val && !V.getAs<nonloc::LazyCompoundVal>())
+    // Returned pair shall be {null, non-null} so reorder states.
+    std::tie(states.second, states.first) = state->assume(*val);
 
-  SValBuilder &svalBuilder = C.getSValBuilder();
-  DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
-  return state->assume(svalBuilder.evalEQ(state, *val, zero));
+  return states;
 }
 
 ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
@@ -299,8 +300,7 @@
     return nullptr;
 
   ProgramStateRef stateNull, stateNonNull;
-  std::tie(stateNull, stateNonNull) =
-      assumeZero(C, State, l, Arg.Expression->getType());
+  std::tie(stateNull, stateNonNull) = assumeZero(State, l);
 
   if (stateNull && !stateNonNull) {
     if (Filter.CheckCStringNullArg) {
@@ -1071,8 +1071,7 @@
     CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy);
 
     ProgramStateRef StateNullChar, StateNonNullChar;
-    std::tie(StateNullChar, StateNonNullChar) =
-        assumeZero(C, State, CharVal, Ctx.UnsignedCharTy);
+    std::tie(StateNullChar, StateNonNullChar) = assumeZero(State, CharVal);
 
     if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
         !StateNonNullChar) {
@@ -1133,11 +1132,9 @@
   // See if the size argument is zero.
   const LocationContext *LCtx = C.getLocationContext();
   SVal sizeVal = state->getSVal(Size.Expression, LCtx);
-  QualType sizeTy = Size.Expression->getType();
 
   ProgramStateRef stateZeroSize, stateNonZeroSize;
-  std::tie(stateZeroSize, stateNonZeroSize) =
-      assumeZero(C, state, sizeVal, sizeTy);
+  std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(state, sizeVal);
 
   // Get the value of the Dest.
   SVal destVal = state->getSVal(Dest.Expression, LCtx);
@@ -1287,11 +1284,9 @@
 
   // See if the size argument is zero.
   SVal sizeVal = State->getSVal(Size.Expression, LCtx);
-  QualType sizeTy = Size.Expression->getType();
 
   ProgramStateRef stateZeroSize, stateNonZeroSize;
-  std::tie(stateZeroSize, stateNonZeroSize) =
-      assumeZero(C, State, sizeVal, sizeTy);
+  std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(State, sizeVal);
 
   // If the size can be zero, the result will be 0 in that case, and we don't
   // have to check either of the buffers.
@@ -1367,8 +1362,7 @@
     SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
 
     ProgramStateRef stateZeroSize, stateNonZeroSize;
-    std::tie(stateZeroSize, stateNonZeroSize) =
-      assumeZero(C, state, maxlenVal, maxlenExpr->getType());
+    std::tie(stateZeroSize, stateNonZeroSize) = assumeZero(state, maxlenVal);
 
     // If the size can be zero, the result will be 0 in that case, and we don't
     // have to check the string itself.
@@ -1706,7 +1700,7 @@
         // as the last element accessed, so n == 0 is problematic.
         ProgramStateRef StateZeroSize, StateNonZeroSize;
         std::tie(StateZeroSize, StateNonZeroSize) =
-            assumeZero(C, state, *lenValNL, sizeTy);
+            assumeZero(state, *lenValNL);
 
         // If the size is known to be zero, we're done.
         if (StateZeroSize && !StateNonZeroSize) {
@@ -2177,10 +2171,9 @@
   // See if the size argument is zero.
   const LocationContext *LCtx = C.getLocationContext();
   SVal SizeVal = C.getSVal(Size.Expression);
-  QualType SizeTy = Size.Expression->getType();
 
   ProgramStateRef ZeroSize, NonZeroSize;
-  std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy);
+  std::tie(ZeroSize, NonZeroSize) = assumeZero(State, SizeVal);
 
   // Get the value of the memory area.
   SVal BufferPtrVal = C.getSVal(Buffer.Expression);
@@ -2225,11 +2218,9 @@
 
   // See if the size argument is zero.
   SVal SizeVal = C.getSVal(Size.Expression);
-  QualType SizeTy = Size.Expression->getType();
 
   ProgramStateRef StateZeroSize, StateNonZeroSize;
-  std::tie(StateZeroSize, StateNonZeroSize) =
-    assumeZero(C, State, SizeVal, SizeTy);
+  std::tie(StateZeroSize, StateNonZeroSize) = assumeZero(State, SizeVal);
 
   // If the size is zero, there won't be any actual memory access,
   // In this case we just return.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to