]> granicus.if.org Git - clang/commitdiff
[analyzer] Fix analyzer warnings on analyzer.
authorArtem Dergachev <artem.dergachev@gmail.com>
Wed, 28 Aug 2019 18:44:38 +0000 (18:44 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Wed, 28 Aug 2019 18:44:38 +0000 (18:44 +0000)
Write tests for the actual crash that was found. Write comments and refactor
code around 17 style bugs and suppress 3 false positives.

Differential Revision: https://reviews.llvm.org/D66847

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370246 91177308-0d34-0410-b5e6-96231b3b80d8

21 files changed:
include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
lib/StaticAnalyzer/Checkers/MallocChecker.cpp
lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
lib/StaticAnalyzer/Core/CheckerHelpers.cpp
lib/StaticAnalyzer/Core/ExprEngineC.cpp
lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
lib/StaticAnalyzer/Core/MemRegion.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp
test/Analysis/cstring-syntax-weird.c [new file with mode: 0644]
test/Analysis/cstring-syntax-weird2.c [new file with mode: 0644]
test/Analysis/cstring-syntax.c

index 071e35085a5f93f6a0620e18186c56a7e7ef3849..71cbbe28fc2585592f3152f92fb75c700ab53cb3 100644 (file)
@@ -169,6 +169,7 @@ public:
   Kind getKind() const { return kind; }
 
   template<typename RegionTy> const RegionTy* getAs() const;
+  template<typename RegionTy> const RegionTy* castAs() const;
 
   virtual bool isBoundable() const { return false; }
 
@@ -1231,6 +1232,11 @@ const RegionTy* MemRegion::getAs() const {
   return nullptr;
 }
 
+template<typename RegionTy>
+const RegionTy* MemRegion::castAs() const {
+  return cast<RegionTy>(this);
+}
+
 //===----------------------------------------------------------------------===//
 // MemRegionManager - Factory object for creating regions.
 //===----------------------------------------------------------------------===//
index b828ac059236399889f28036226e061a51c01d27..d84fcc69a492582da966c7f3e9e7eaacffbde0d6 100644 (file)
@@ -156,14 +156,21 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
   const Expr *DstArg = CE->getArg(0);
   const Expr *LenArg = CE->getArg(2);
 
-  const auto *DstArgDecl = dyn_cast<DeclRefExpr>(DstArg->IgnoreParenImpCasts());
-  const auto *LenArgDecl = dyn_cast<DeclRefExpr>(LenArg->IgnoreParenLValueCasts());
+  const auto *DstArgDRE = dyn_cast<DeclRefExpr>(DstArg->IgnoreParenImpCasts());
+  const auto *LenArgDRE =
+      dyn_cast<DeclRefExpr>(LenArg->IgnoreParenLValueCasts());
   uint64_t DstOff = 0;
   if (isSizeof(LenArg, DstArg))
     return false;
+
   // - size_t dstlen = sizeof(dst)
-  if (LenArgDecl) {
-    const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDecl->getDecl());
+  if (LenArgDRE) {
+    const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDRE->getDecl());
+    // If it's an EnumConstantDecl instead, then we're missing out on something.
+    if (!LenArgVal) {
+      assert(isa<EnumConstantDecl>(LenArgDRE->getDecl()));
+      return false;
+    }
     if (LenArgVal->getInit())
       LenArg = LenArgVal->getInit();
   }
@@ -177,9 +184,10 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
     // Case when there is pointer arithmetic on the destination buffer
     // especially when we offset from the base decreasing the
     // buffer length accordingly.
-    if (!DstArgDecl) {
-      if (const auto *BE = dyn_cast<BinaryOperator>(DstArg->IgnoreParenImpCasts())) {
-        DstArgDecl = dyn_cast<DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
+    if (!DstArgDRE) {
+      if (const auto *BE =
+              dyn_cast<BinaryOperator>(DstArg->IgnoreParenImpCasts())) {
+        DstArgDRE = dyn_cast<DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
         if (BE->getOpcode() == BO_Add) {
           if ((IL = dyn_cast<IntegerLiteral>(BE->getRHS()->IgnoreParenImpCasts()))) {
             DstOff = IL->getValue().getZExtValue();
@@ -187,8 +195,9 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
         }
       }
     }
-    if (DstArgDecl) {
-      if (const auto *Buffer = dyn_cast<ConstantArrayType>(DstArgDecl->getType())) {
+    if (DstArgDRE) {
+      if (const auto *Buffer =
+              dyn_cast<ConstantArrayType>(DstArgDRE->getType())) {
         ASTContext &C = BR.getContext();
         uint64_t BufferLen = C.getTypeSize(Buffer) / 8;
         auto RemainingBufferLen = BufferLen - DstOff;
index 3f1c213a564787cee8032da6a34c9899f8fe3c7f..7f32b15ae92f7e9defbeedc1cc69baad74723f61 100644 (file)
@@ -204,6 +204,8 @@ void WalkAST::VisitForStmt(ForStmt *FS) {
 // Implements: CERT security coding advisory FLP-30.
 //===----------------------------------------------------------------------===//
 
+// Returns either 'x' or 'y', depending on which one of them is incremented
+// in 'expr', or nullptr if none of them is incremented.
 static const DeclRefExpr*
 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
   expr = expr->IgnoreParenCasts();
@@ -289,14 +291,15 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
 
   // Does either variable appear in increment?
   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
-
   if (!drInc)
     return;
 
+  const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
+  assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
+
   // Emit the error.  First figure out which DeclRefExpr in the condition
   // referenced the compared variable.
-  assert(drInc->getDecl());
-  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
+  const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
 
   SmallVector<SourceRange, 2> ranges;
   SmallString<256> sbuf;
index f2d1d018914d69c5ea12b79ca2132fecd90d1eea..e1dcf2c1a18f2d6ad73bc1f1cf204c697bddee6e 100644 (file)
@@ -394,11 +394,11 @@ static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl(
   }
 
   const auto *SuperOfTo =
-      To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>();
+      To->getObjectType()->getSuperClassType()->castAs<ObjCObjectType>();
   assert(SuperOfTo);
   QualType SuperPtrOfToQual =
       C.getObjCObjectPointerType(QualType(SuperOfTo, 0));
-  const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>();
+  const auto *SuperPtrOfTo = SuperPtrOfToQual->castAs<ObjCObjectPointerType>();
   if (To->isUnspecialized())
     return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo,
                                               C);
@@ -827,16 +827,15 @@ void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
   if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class &&
       Sel.getAsString() == "class") {
     QualType ReceiverType = MessageExpr->getClassReceiver();
-    const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>();
+    const auto *ReceiverClassType = ReceiverType->castAs<ObjCObjectType>();
+    if (!ReceiverClassType->isSpecialized())
+      return;
+
     QualType ReceiverClassPointerType =
         C.getASTContext().getObjCObjectPointerType(
             QualType(ReceiverClassType, 0));
-
-    if (!ReceiverClassType->isSpecialized())
-      return;
     const auto *InferredType =
-        ReceiverClassPointerType->getAs<ObjCObjectPointerType>();
-    assert(InferredType);
+        ReceiverClassPointerType->castAs<ObjCObjectPointerType>();
 
     State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
     C.addTransition(State);
index 3c1a79dd318e8756a06686aeadf597d0c1b03925..5fe7ba5578648c04fda1cc5ca34a2c70b23f0ad1 100644 (file)
@@ -567,7 +567,8 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
   if (Func->isOverloadedOperator()) {
     const auto Op = Func->getOverloadedOperator();
     if (isAssignmentOperator(Op)) {
-      const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call);
+      // Overloaded 'operator=' must be a non-static member function.
+      const auto *InstCall = cast<CXXInstanceCall>(&Call);
       if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
         handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
                      Call.getArgSVal(0));
index 19bcf47286e3bcd3370dce22250527b71491652f..dd83b0b952e7f2baa32350aec9c76ace45ffa83b 100644 (file)
@@ -882,18 +882,17 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
 
 void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call,
                                              CheckerContext &C) const {
-  const Decl *D = Call.getDecl();
-  if (D && isa<FunctionDecl>(D)) {
-    const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
-    auto formals = FD->parameters();
-    for (unsigned i = 0,
-                  ei = std::min(unsigned(formals.size()), Call.getNumArgs());
-         i != ei; ++i) {
-      if (isAnnotatedAsTakingLocalized(formals[i])) {
-        auto actual = Call.getArgSVal(i);
-        if (hasNonLocalizedState(actual, C)) {
-          reportLocalizationError(actual, Call, C, i + 1);
-        }
+  const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+  if (!FD)
+    return;
+
+  auto formals = FD->parameters();
+  for (unsigned i = 0, ei = std::min(static_cast<unsigned>(formals.size()),
+                                     Call.getNumArgs()); i != ei; ++i) {
+    if (isAnnotatedAsTakingLocalized(formals[i])) {
+      auto actual = Call.getArgSVal(i);
+      if (hasNonLocalizedState(actual, C)) {
+        reportLocalizationError(actual, Call, C, i + 1);
       }
     }
   }
index f16b2606ce4fdd8b244de0ffc5180402666bf038..d87e30782b74744defab635ffc4c4e93fd0a9eca 100644 (file)
@@ -91,11 +91,13 @@ PathDiagnosticPieceRef MPIBugReporter::RequestNodeVisitor::VisitNode(
     return nullptr;
 
   const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
+  assert(Req && "The region must be tracked and alive, given that we've "
+                "just emitted a report against it");
   const Request *const PrevReq =
       N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
 
   // Check if request was previously unused or in a different state.
-  if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) {
+  if (!PrevReq || (Req->CurrentState != PrevReq->CurrentState)) {
     IsNodeFound = true;
 
     ProgramPoint P = N->getFirstPred()->getLocation();
index 4a1aa3d47a63779a6ca68ed1f6ae7b6d42c64c00..8abd938c22168e14baaea0a91c63eda044407bd7 100644 (file)
@@ -1132,14 +1132,13 @@ ProgramStateRef MallocChecker::addExtentSize(CheckerContext &C,
     // Store the extent size for the (symbolic)region
     // containing the elements.
     Region = Target.getAsRegion()
-                 ->getAs<SubRegion>()
+                 ->castAs<SubRegion>()
                  ->StripCasts()
-                 ->getAs<SubRegion>();
+                 ->castAs<SubRegion>();
   } else {
     ElementCount = svalBuilder.makeIntVal(1, true);
-    Region = Target.getAsRegion()->getAs<SubRegion>();
+    Region = Target.getAsRegion()->castAs<SubRegion>();
   }
-  assert(Region);
 
   // Set the region's extent equal to the Size in Bytes.
   QualType ElementType = NE->getAllocatedType();
@@ -3066,8 +3065,12 @@ PathDiagnosticPieceRef MallocChecker::MallocBugVisitor::VisitNode(
     }
   }
 
-  if (Msg.empty())
+  if (Msg.empty()) {
+    // Silence a memory leak warning by MallocChecker in MallocChecker.cpp :)
+    assert(!StackHint && "Memory leak!");
     return nullptr;
+  }
+
   assert(StackHint);
 
   // Generate the extra diagnostic.
index 2eb4d7141e2846150e5a3cfb387b84394342c58a..b5881a9e65338dc604051a2590dcbc4e5df1e301 100644 (file)
@@ -183,7 +183,7 @@ public:
       QualType CastedType = i->CastedExpr->getType();
       if (!CastedType->isPointerType())
         continue;
-      QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType();
+      QualType PointeeType = CastedType->getPointeeType();
       if (PointeeType->isVoidType())
         continue;
 
index 47322d6fffc4f70d52cddf50ea2624b16a4dc5eb..4ce82f225b94672f2d4d584baa47d690d02d83b8 100644 (file)
@@ -119,12 +119,12 @@ const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region,
                                                      AllocKind &AKind,
                                                      CheckerContext &C) const {
   assert(Region);
-  while (Region->getKind() == MemRegion::Kind::CXXBaseObjectRegionKind) {
-    Region = Region->getAs<CXXBaseObjectRegion>()->getSuperRegion();
+  while (const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
+    Region = BaseRegion->getSuperRegion();
     Polymorphic = true;
   }
-  if (Region->getKind() == MemRegion::Kind::ElementRegionKind) {
-    Region = Region->getAs<ElementRegion>()->getSuperRegion();
+  if (const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
+    Region = ElemRegion->getSuperRegion();
   }
 
   ProgramStateRef State = C.getState();
@@ -137,7 +137,7 @@ const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region,
   }
   // When the region is symbolic and we do not have any information about it,
   // assume that this is an array to avoid false positives.
-  if (Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
+  if (isa<SymbolicRegion>(Region))
     return Region;
 
   // No AllocKind stored and not symbolic, assume that it points to a single
index 9ed536807ee43be18170a250a7494e87a7255617..f06d6b8c7175673132c434eb74ba3366c6cc402e 100644 (file)
@@ -85,7 +85,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
     }
 
     if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
-      const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+      const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
       ex = VD->getInit();
     }
 
index 54d4e48ab8d9ded3fb8fd287fe501760793a3fa1..f0dd0bf813affb7a9d73f54da3651ab27d26bbf0 100644 (file)
@@ -260,12 +260,13 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
       break;
   }
 
-  while (R->getAs<CXXBaseObjectRegion>()) {
+  while (isa<CXXBaseObjectRegion>(R)) {
     NeedsCastBack = true;
-
-    if (!isa<TypedValueRegion>(R->getSuperRegion()))
+    const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
+    if (!SuperR)
       break;
-    R = R->getSuperRegion()->getAs<TypedValueRegion>();
+
+    R = SuperR;
   }
 
   return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
index 874e231bb0bb571a096fe6735dc9530acc948d5b..903ba04491f529be0c1c70ad3162e02ff339524c 100644 (file)
@@ -104,7 +104,8 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call,
     return;
 
   ProgramStateRef State = C.getState();
-  const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  // Member calls are always represented by a call-expression.
+  const auto *CE = cast<CallExpr>(Call.getOriginExpr());
   if (!isVirtualCall(CE))
     return;
 
index 34cdc9db699db56566b4e63828b6c47f5686e776..11693132de6877b36c1ead2d92ee1dc72b902bcf 100644 (file)
@@ -91,7 +91,7 @@ parseAssignment(const Stmt *S) {
   } else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
     // Initialization
     assert(PD->isSingleDecl() && "We process decls one by one");
-    VD = dyn_cast_or_null<VarDecl>(PD->getSingleDecl());
+    VD = cast<VarDecl>(PD->getSingleDecl());
     RHS = VD->getAnyInitializer();
   }
 
index f436650fbdd9b2fb51191a03afe09314cb025e5d..02a398c77ac88d4ed87f81e74f9b55f1d14916d9 100644 (file)
@@ -850,8 +850,7 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE,
   if (OOE->EvaluateAsInt(Result, getContext())) {
     APSInt IV = Result.Val.getInt();
     assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
-    assert(OOE->getType()->isBuiltinType());
-    assert(OOE->getType()->getAs<BuiltinType>()->isInteger());
+    assert(OOE->getType()->castAs<BuiltinType>()->isInteger());
     assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
     SVal X = svalBuilder.makeIntVal(IV);
     B.generateNode(OOE, Pred,
index 91afde603ca939533dd5c6b9712250609f0f61ae..83303d722f2719afca14159e1c28971fe038ff87 100644 (file)
@@ -803,9 +803,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
   if (CNE->isArray()) {
     // FIXME: allocating an array requires simulating the constructors.
     // For now, just return a symbolicated region.
-    if (const SubRegion *NewReg =
-            dyn_cast_or_null<SubRegion>(symVal.getAsRegion())) {
-      QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+    if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) {
+      QualType ObjTy = CNE->getType()->getPointeeType();
       const ElementRegion *EleReg =
           getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
       Result = loc::MemRegionVal(EleReg);
index f763701af7fb186c6b87bdfdcdc9f7b7af0b3ded..c7b280adcd9be886ee3dce89ab239e1da5e17b92 100644 (file)
@@ -1075,7 +1075,7 @@ MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
                                          const SubRegion *Super,
                                          bool IsVirtual) {
   if (isa<TypedValueRegion>(Super)) {
-    assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
+    assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
     (void)&isValidBaseClass;
 
     if (IsVirtual) {
@@ -1426,6 +1426,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {
     case MemRegion::FieldRegionKind: {
       const auto *FR = cast<FieldRegion>(R);
       R = FR->getSuperRegion();
+      assert(R);
 
       const RecordDecl *RD = FR->getDecl()->getParent();
       if (RD->isUnion() || !RD->isCompleteDefinition()) {
index 8e4fd7d19b7b2d488f234a2557e75a8c917de0d8..5d2ef59e2d66b6af166b23f0ff93f742b0be1667 100644 (file)
@@ -2291,8 +2291,7 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
                                                  const TypedValueRegion* R,
                                                  SVal V) {
   QualType T = R->getValueType();
-  assert(T->isVectorType());
-  const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
+  const VectorType *VT = T->castAs<VectorType>(); // Use castAs for typedefs.
 
   // Handle lazy compound values and symbolic values.
   if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
@@ -2377,7 +2376,7 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
   QualType T = R->getValueType();
   assert(T->isStructureOrClassType());
 
-  const RecordType* RT = T->getAs<RecordType>();
+  const RecordType* RT = T->castAs<RecordType>();
   const RecordDecl *RD = RT->getDecl();
 
   if (!RD->isCompleteDefinition())
diff --git a/test/Analysis/cstring-syntax-weird.c b/test/Analysis/cstring-syntax-weird.c
new file mode 100644 (file)
index 0000000..9a58f16
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=unix.cstring.BadSizeArg \
+// RUN:                    -verify %s
+
+// expected-no-diagnostics
+
+typedef __SIZE_TYPE__ size_t;
+// The last parameter is normally size_t but the test is about the abnormal
+// situation when it's not a size_t.
+size_t strlcpy(char *, const char *, int);
+
+enum WeirdDecl {
+  AStrangeWayToSpecifyStringLengthCorrectly = 10UL,
+  AStrangeWayToSpecifyStringLengthIncorrectly = 5UL
+};
+void testWeirdDecls(const char *src) {
+  char dst[10];
+  strlcpy(dst, src, AStrangeWayToSpecifyStringLengthCorrectly); // no-crash
+  strlcpy(dst, src, AStrangeWayToSpecifyStringLengthIncorrectly); // no-crash // no-warning
+}
diff --git a/test/Analysis/cstring-syntax-weird2.c b/test/Analysis/cstring-syntax-weird2.c
new file mode 100644 (file)
index 0000000..a0f2853
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=unix.cstring.BadSizeArg \
+// RUN:                    -verify %s
+
+// expected-no-diagnostics
+
+typedef __SIZE_TYPE__ size_t;
+// The last parameter is normally size_t but the test is about the abnormal
+// situation when it's not a size_t.
+size_t strlcpy(char *, const char *, void (*)());
+
+void foo();
+
+void testWeirdDecls(const char *src) {
+  char dst[10];
+  strlcpy(dst, src, foo); // no-crash
+  strlcpy(dst, src, &foo); // no-crash
+}
index f01de36c1afb8fd62fb5dc8fcdbca4cd5e9f5c7d..8ac971fe24127e33896c73fd173d956fa640616b 100644 (file)
@@ -1,7 +1,18 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
-// RUN: %clang_analyze_cc1 -triple armv7-a15-linux -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
-// RUN: %clang_analyze_cc1 -triple aarch64_be-none-linux-gnu -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
-// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strncat-size -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify %s\
+// RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     \
+// RUN:                    -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify %s\
+// RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     \
+// RUN:                    -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument\
+// RUN:                    -triple armv7-a15-linux
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify %s\
+// RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     \
+// RUN:                    -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument\
+// RUN:                    -triple aarch64_be-none-linux-gnu
+// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify %s\
+// RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     \
+// RUN:                    -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument\
+// RUN:                    -triple i386-apple-darwin10
 
 typedef __SIZE_TYPE__ size_t;
 char  *strncat(char *, const char *, size_t);