baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, Charusso.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, gamesh411, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun, 
whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

llvm::isa<>() and llvm::isa_and_not_null<>() template functions recently became 
variadic. Unfortunately this causes crashes in case of isa_and_not_null<>() and 
incorrect behavior in isa<>(). This patch fixes this issue.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85728

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/test/Analysis/Inputs/llvm.h
  clang/test/Analysis/cast-value-logic.cpp
  clang/test/Analysis/cast-value-notes.cpp

Index: clang/test/Analysis/cast-value-notes.cpp
===================================================================
--- clang/test/Analysis/cast-value-notes.cpp
+++ clang/test/Analysis/cast-value-notes.cpp
@@ -13,20 +13,22 @@
   const T *getAs() const;
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {};
 } // namespace clang
 
 using namespace llvm;
 using namespace clang;
 
-void evalReferences(const Shape &S) {
+/*void evalReferences(const Shape &S) {
   const auto &C = dyn_cast<Circle>(S);
   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
   // expected-note@-2 {{Dereference of null pointer}}
   // expected-warning@-3 {{Dereference of null pointer}}
-}
+  }*/
 
-void evalNonNullParamNonNullReturnReference(const Shape &S) {
+void evalNonNullParamNonNullReturnReference(const Shape *S) {
   // Unmodeled cast from reference to pointer.
   const auto *C = dyn_cast_or_null<Circle>(S);
   // expected-note@-1 {{'C' initialized here}}
@@ -43,12 +45,36 @@
     return;
   }
 
+  if (dyn_cast_or_null<Rectangle>(C)) {
+    // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
+  if (dyn_cast_or_null<Hexagon>(C)) {
+    // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
   if (isa<Triangle>(C)) {
     // expected-note@-1 {{'C' is not a 'Triangle'}}
     // expected-note@-2 {{Taking false branch}}
     return;
   }
 
+  if (isa<Triangle, Rectangle>(C)) {
+    // expected-note@-1 {{'C' is not a 'Triangle'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
+  if (isa<Triangle, Rectangle, Hexagon>(C)) {
+    // expected-note@-1 {{'C' is not a 'Triangle'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
   if (isa<Circle>(C)) {
     // expected-note@-1 {{'C' is a 'Circle'}}
     // expected-note@-2 {{Taking true branch}}
@@ -58,9 +84,29 @@
     // expected-note@-2 {{Division by zero}}
     // expected-warning@-3 {{Division by zero}}
   }
+
+  if (isa<Circle, Rectangle>(C)) {
+    // expected-note@-1 {{'C' is a 'Circle'}}
+    // expected-note@-2 {{Taking true branch}}
+
+    (void)(1 / !C);
+    // expected-note@-1 {{'C' is non-null}}
+    // expected-note@-2 {{Division by zero}}
+    // expected-warning@-3 {{Division by zero}}
+  }
+
+  if (isa<Circle, Rectangle, Hexagon>(C)) {
+    // expected-note@-1 {{'C' is a 'Circle'}}
+    // expected-note@-2 {{Taking true branch}}
+
+    (void)(1 / !C);
+    // expected-note@-1 {{'C' is non-null}}
+    // expected-note@-2 {{Division by zero}}
+    // expected-warning@-3 {{Division by zero}}
+  }
 }
 
-void evalNonNullParamNonNullReturn(const Shape *S) {
+/*void evalNonNullParamNonNullReturn(const Shape *S) {
   const auto *C = cast<Circle>(S);
   // expected-note@-1 {{'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
@@ -153,3 +199,4 @@
   // expected-note@-1 {{Division by zero}}
   // expected-warning@-2 {{Division by zero}}
 }
+*/
Index: clang/test/Analysis/cast-value-logic.cpp
===================================================================
--- clang/test/Analysis/cast-value-logic.cpp
+++ clang/test/Analysis/cast-value-logic.cpp
@@ -19,6 +19,8 @@
   virtual double area();
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {
 public:
   ~Circle();
@@ -39,6 +41,23 @@
     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
 }
 
+void test_regions_isa_variadic(const Shape *A, const Shape *B) {
+  if (isa<Triangle, Rectangle, Hexagon>(A) &&
+      !isa<Rectangle, Hexagon, Circle>(B))
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull<Circle>(A) && !isa_and_nonnull<Circle>(B))
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull<Triangle, Rectangle, Hexagon>(A) &&
+      !isa_and_nonnull<Rectangle, Hexagon, Circle>(B))
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
 namespace test_cast {
 void evalLogic(const Shape *S) {
   const Circle *C = cast<Circle>(S);
Index: clang/test/Analysis/Inputs/llvm.h
===================================================================
--- clang/test/Analysis/Inputs/llvm.h
+++ clang/test/Analysis/Inputs/llvm.h
@@ -19,11 +19,19 @@
 template <class X, class Y>
 const X *dyn_cast_or_null(Y &Value);
 
-template <class X, class Y>
-bool isa(Y Value);
-
-template <class X, class Y>
-bool isa_and_nonnull(Y Value);
+template <class X, class Y> inline bool isa(const Y &Val);
+
+template <typename First, typename Second, typename... Rest, typename Y>
+inline bool isa(const Y &Val) {
+  return isa<First>(Val) || isa<Second, Rest...>(Val);
+}
+
+template <typename... X, class Y>
+inline bool isa_and_nonnull(const Y &Val) {
+  if (!Val)
+    return false;
+  return isa<X...>(Val);
+}
 
 template <typename X, typename Y>
 std::unique_ptr<X> cast(std::unique_ptr<Y> &&Value);
Index: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -168,6 +168,19 @@
   if (Call.getNumArgs() > 0) {
     Object = Call.getArgExpr(0);
     CastFromTy = Call.parameters()[0]->getType();
+    llvm::errs()<<"<<<Cast>>>\n";
+    llvm::errs()<<"CastFromType:\n";
+    CastFromTy->dump();
+    llvm::errs()<<"\n";
+    llvm::errs()<<"Desugared:\n";
+    CastFromTy->getUnqualifiedDesugaredType()->dump();
+    llvm::errs()<<"\n";
+    if (CastFromTy->isPointerType()) {
+      llvm::errs()<<"Desugared pointer:\n";
+      cast<PointerType>(CastFromTy.getTypePtr())->desugar()->dump();
+      llvm::errs()<<"\n";
+
+    }
   } else {
     Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
     CastFromTy = Object->getType();
@@ -185,6 +198,8 @@
   const MemRegion *MR = DV.getAsRegion();
   const DynamicCastInfo *CastInfo =
       getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
+  if (CastInfo && CastInfo->succeeds()) llvm::errs()<<"  Casting succeeds.\n";
+  if (CastInfo && CastInfo->fails()) llvm::errs()<<"  Casting fails.\n";
 
   // We assume that every checked cast succeeds.
   bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
@@ -198,14 +213,24 @@
   // Check for infeasible casts.
   if (isInfeasibleCast(CastInfo, CastSucceeds)) {
     C.generateSink(State, C.getPredecessor());
+    llvm::errs()<<"Infeasible cast.\n";
     return;
   }
 
   // Store the type and the cast information.
   bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
-  if (!IsKnownCast || IsCheckedCast)
+  llvm::errs()<<"CastInfo: "<<(CastInfo?"exists":"none")<<"\n";
+  llvm::errs()<<"IsCheckedCast: "<<(IsCheckedCast?"true":"false")<<"\n";
+  llvm::errs()<<"CastFromTy == CastToTy: "<<((CastFromTy == CastToTy)?"true":"false")<<"\n";
+  if (!IsKnownCast || IsCheckedCast) {
+    llvm::errs()<<"Setting "<<(CastSucceeds?"positive":"negative")<<" dynamic type info for "<<MR<<":\n";
+    CastToTy.dump();
+    llvm::errs()<<"Static type:\n";
+    CastFromTy.dump();
+    llvm::errs()<<"\n";
     State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
                                       CastSucceeds);
+  }
 
   SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
                         : C.getSValBuilder().makeNull();
@@ -220,40 +245,96 @@
                                     bool IsInstanceOf) {
   const FunctionDecl *FD = Call.getDecl()->getAsFunction();
   QualType CastFromTy = Call.parameters()[0]->getType();
-  QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
-  if (CastFromTy->isPointerType())
-    CastToTy = C.getASTContext().getPointerType(CastToTy);
-  else if (CastFromTy->isReferenceType())
-    CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
-  else
-    return;
+  llvm::errs()<<"<<<isa>>>\n";
+  llvm::errs()<<"CastFromType:\n";
+  CastFromTy->dump();
+  llvm::errs()<<"\n";
+  llvm::errs()<<"Desugared:\n";
+  CastFromTy->getUnqualifiedDesugaredType()->dump();
+  llvm::errs()<<"\n";
+  assert(CastFromTy->isReferenceType());
+  CastFromTy = CastFromTy.getNonReferenceType();
+  llvm::errs()<<"NonRef:\n";
+  CastFromTy->dump();
+  llvm::errs()<<"\n";
+  assert(isa<SubstTemplateTypeParmType>(CastFromTy.getTypePtr()));
+  CastFromTy = cast<SubstTemplateTypeParmType>(
+      CastFromTy.getTypePtr())->getReplacementType();
+  llvm::errs()<<"Replacement:\n";
+  CastFromTy->dump();
+  llvm::errs()<<"\n";
+  SmallVector<QualType, 4> CastToTyVec;
+  for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
+       ++idx) {
+    TemplateArgument CastToTempArg =
+      FD->getTemplateSpecializationArgs()->get(idx);
+    switch (CastToTempArg.getKind()) {
+    default:
+      llvm_unreachable("Invalid template argument for isa<> or "
+                       "isa_and_nonnull<>");
+    case TemplateArgument::Type:
+      CastToTyVec.push_back(CastToTempArg.getAsType());
+      break;
+    case TemplateArgument::Pack:
+      for (TemplateArgument ArgInPack: CastToTempArg.pack_elements()) 
+        CastToTyVec.push_back(ArgInPack.getAsType());
+      break;
+    }
+  }
 
+  llvm::errs()<<"Checking instance of: ";
+  CastFromTy.dump();
+  llvm::errs()<<"\n";
   const MemRegion *MR = DV.getAsRegion();
-  const DynamicCastInfo *CastInfo =
-      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
+  bool Success = false;
+  for (QualType CastToTy: CastToTyVec) {
+    llvm::errs()<<"Processing (IsInstanceOf is "<<(IsInstanceOf?"true":"false")<<"): ";
+    CastToTy.dump();
+    llvm::errs()<<"\n";
+    if (CastFromTy->isPointerType())
+      CastToTy = C.getASTContext().getPointerType(CastToTy);
+    else if (CastFromTy->isReferenceType())
+      CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
+    else
+      return;
 
-  bool CastSucceeds;
-  if (CastInfo)
-    CastSucceeds = IsInstanceOf && CastInfo->succeeds();
-  else
-    CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
+    const DynamicCastInfo *CastInfo =
+      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
+    if (CastInfo && CastInfo->succeeds()) llvm::errs()<<"  Casting succeeds.\n";
+    if (CastInfo && CastInfo->fails()) llvm::errs()<<"  Casting fails.\n";
 
-  if (isInfeasibleCast(CastInfo, CastSucceeds)) {
-    C.generateSink(State, C.getPredecessor());
-    return;
+    bool CastSucceeds;
+    if (CastInfo)
+      CastSucceeds = IsInstanceOf && CastInfo->succeeds();
+    else
+      CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
+    llvm::errs()<<"  CastSucceeds: "<<(CastSucceeds?"true":"false")<<"\n";
+
+    // Store the type and the cast information.
+    bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
+    ProgramStateRef NewState = State;
+    if (!IsKnownCast)
+      NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
+                                           IsInstanceOf);
+
+    if (CastSucceeds) {
+      Success = true;
+      C.addTransition(
+          NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                             C.getSValBuilder().makeTruthVal(true)),
+          getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
+                     IsKnownCast));
+    } else if (CastInfo && CastInfo->succeeds()) {
+      C.generateSink(NewState, C.getPredecessor());
+      return;
+    }
   }
 
-  // Store the type and the cast information.
-  bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
-  if (!IsKnownCast)
-    State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
-                                      IsInstanceOf);
-
-  C.addTransition(
-      State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
-                      C.getSValBuilder().makeTruthVal(CastSucceeds)),
-      getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
-                 IsKnownCast));
+  if (!Success) {
+    C.addTransition(
+        State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                        C.getSValBuilder().makeTruthVal(false)));
+  }
 }
 
 //===----------------------------------------------------------------------===//
@@ -402,8 +483,11 @@
     QualType ParamT = Call.parameters()[0]->getType();
     QualType ResultT = Call.getResultType();
     if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
-        !(ParamT->isReferenceType() && ResultT->isReferenceType()))
+        !(ParamT->isReferenceType() && ResultT->isReferenceType())) {
+      llvm::errs()<<"Neither pointer, nor reference:\n";
+      Call.dump();
       return false;
+    }
 
     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
     break;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to