Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -169,6 +169,7 @@ Kind getKind() const { return kind; } template const RegionTy* getAs() const; + template const RegionTy* castAs() const; virtual bool isBoundable() const { return false; } @@ -1231,6 +1232,11 @@ return nullptr; } +template +const RegionTy* MemRegion::castAs() const { + return cast(this); +} + //===----------------------------------------------------------------------===// // MemRegionManager - Factory object for creating regions. //===----------------------------------------------------------------------===// Index: clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -156,14 +156,21 @@ const Expr *DstArg = CE->getArg(0); const Expr *LenArg = CE->getArg(2); - const auto *DstArgDecl = dyn_cast(DstArg->IgnoreParenImpCasts()); - const auto *LenArgDecl = dyn_cast(LenArg->IgnoreParenLValueCasts()); + const auto *DstArgDRE = dyn_cast(DstArg->IgnoreParenImpCasts()); + const auto *LenArgDRE = + dyn_cast(LenArg->IgnoreParenLValueCasts()); uint64_t DstOff = 0; if (isSizeof(LenArg, DstArg)) return false; + // - size_t dstlen = sizeof(dst) - if (LenArgDecl) { - const auto *LenArgVal = dyn_cast(LenArgDecl->getDecl()); + if (LenArgDRE) { + const auto *LenArgVal = dyn_cast(LenArgDRE->getDecl()); + // If it's an EnumConstantDecl instead, then we're missing out on something. + if (!LenArgVal) { + assert(isa(LenArgDRE->getDecl())); + return false; + } if (LenArgVal->getInit()) LenArg = LenArgVal->getInit(); } @@ -177,9 +184,10 @@ // 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(DstArg->IgnoreParenImpCasts())) { - DstArgDecl = dyn_cast(BE->getLHS()->IgnoreParenImpCasts()); + if (!DstArgDRE) { + if (const auto *BE = + dyn_cast(DstArg->IgnoreParenImpCasts())) { + DstArgDRE = dyn_cast(BE->getLHS()->IgnoreParenImpCasts()); if (BE->getOpcode() == BO_Add) { if ((IL = dyn_cast(BE->getRHS()->IgnoreParenImpCasts()))) { DstOff = IL->getValue().getZExtValue(); @@ -187,8 +195,9 @@ } } } - if (DstArgDecl) { - if (const auto *Buffer = dyn_cast(DstArgDecl->getType())) { + if (DstArgDRE) { + if (const auto *Buffer = + dyn_cast(DstArgDRE->getType())) { ASTContext &C = BR.getContext(); uint64_t BufferLen = C.getTypeSize(Buffer) / 8; auto RemainingBufferLen = BufferLen - DstOff; Index: clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -204,6 +204,8 @@ // 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 @@ // Does either variable appear in increment? const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS); - if (!drInc) return; + const VarDecl *vdInc = cast(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 ranges; SmallString<256> sbuf; Index: clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -394,11 +394,11 @@ } const auto *SuperOfTo = - To->getObjectType()->getSuperClassType()->getAs(); + To->getObjectType()->getSuperClassType()->castAs(); assert(SuperOfTo); QualType SuperPtrOfToQual = C.getObjCObjectPointerType(QualType(SuperOfTo, 0)); - const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs(); + const auto *SuperPtrOfTo = SuperPtrOfToQual->castAs(); if (To->isUnspecialized()) return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo, C); @@ -827,16 +827,15 @@ if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class && Sel.getAsString() == "class") { QualType ReceiverType = MessageExpr->getClassReceiver(); - const auto *ReceiverClassType = ReceiverType->getAs(); + const auto *ReceiverClassType = ReceiverType->castAs(); + if (!ReceiverClassType->isSpecialized()) + return; + QualType ReceiverClassPointerType = C.getASTContext().getObjCObjectPointerType( QualType(ReceiverClassType, 0)); - - if (!ReceiverClassType->isSpecialized()) - return; const auto *InferredType = - ReceiverClassPointerType->getAs(); - assert(InferredType); + ReceiverClassPointerType->castAs(); State = State->set(RetSym, InferredType); C.addTransition(State); Index: clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -567,7 +567,8 @@ if (Func->isOverloadedOperator()) { const auto Op = Func->getOverloadedOperator(); if (isAssignmentOperator(Op)) { - const auto *InstCall = dyn_cast(&Call); + // Overloaded 'operator=' must be a non-static member function. + const auto *InstCall = cast(&Call); if (cast(Func)->isMoveAssignmentOperator()) { handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), Call.getArgSVal(0)); Index: clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -882,18 +882,17 @@ void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - const Decl *D = Call.getDecl(); - if (D && isa(D)) { - const FunctionDecl *FD = dyn_cast(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(Call.getDecl()); + if (!FD) + return; + + auto formals = FD->parameters(); + for (unsigned i = 0, ei = std::min(static_cast(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: clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp +++ clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp @@ -91,11 +91,13 @@ return nullptr; const Request *const Req = N->getState()->get(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(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: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1132,14 +1132,13 @@ // Store the extent size for the (symbolic)region // containing the elements. Region = Target.getAsRegion() - ->getAs() + ->castAs() ->StripCasts() - ->getAs(); + ->castAs(); } else { ElementCount = svalBuilder.makeIntVal(1, true); - Region = Target.getAsRegion()->getAs(); + Region = Target.getAsRegion()->castAs(); } - assert(Region); // Set the region's extent equal to the Size in Bytes. QualType ElementType = NE->getAllocatedType(); @@ -3066,8 +3065,12 @@ } } - 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: clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -183,7 +183,7 @@ QualType CastedType = i->CastedExpr->getType(); if (!CastedType->isPointerType()) continue; - QualType PointeeType = CastedType->getAs()->getPointeeType(); + QualType PointeeType = CastedType->getPointeeType(); if (PointeeType->isVoidType()) continue; Index: clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -119,12 +119,12 @@ AllocKind &AKind, CheckerContext &C) const { assert(Region); - while (Region->getKind() == MemRegion::Kind::CXXBaseObjectRegionKind) { - Region = Region->getAs()->getSuperRegion(); + while (const auto *BaseRegion = dyn_cast(Region)) { + Region = BaseRegion->getSuperRegion(); Polymorphic = true; } - if (Region->getKind() == MemRegion::Kind::ElementRegionKind) { - Region = Region->getAs()->getSuperRegion(); + if (const auto *ElemRegion = dyn_cast(Region)) { + Region = ElemRegion->getSuperRegion(); } ProgramStateRef State = C.getState(); @@ -137,7 +137,7 @@ } // 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(Region)) return Region; // No AllocKind stored and not symbolic, assume that it points to a single Index: clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -85,7 +85,7 @@ } if (const DeclStmt *DS = dyn_cast(StoreE)) { - const VarDecl *VD = dyn_cast(DS->getSingleDecl()); + const VarDecl *VD = cast(DS->getSingleDecl()); ex = VD->getInit(); } Index: clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp +++ clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp @@ -260,12 +260,13 @@ break; } - while (R->getAs()) { + while (isa(R)) { NeedsCastBack = true; - - if (!isa(R->getSuperRegion())) + const auto *SuperR = dyn_cast(R->getSuperRegion()); + if (!SuperR) break; - R = R->getSuperRegion()->getAs(); + + R = SuperR; } return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; Index: clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -104,7 +104,8 @@ return; ProgramStateRef State = C.getState(); - const CallExpr *CE = dyn_cast_or_null(Call.getOriginExpr()); + // Member calls are always represented by a call-expression. + const CallExpr *CE = cast(Call.getOriginExpr()); if (!isVirtualCall(CE)) return; Index: clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -91,7 +91,7 @@ } else if (auto PD = dyn_cast_or_null(S)) { // Initialization assert(PD->isSingleDecl() && "We process decls one by one"); - VD = dyn_cast_or_null(PD->getSingleDecl()); + VD = cast(PD->getSingleDecl()); RHS = VD->getAnyInitializer(); } Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -850,8 +850,7 @@ 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()->isInteger()); + assert(OOE->getType()->castAs()->isInteger()); assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); SVal X = svalBuilder.makeIntVal(IV); B.generateNode(OOE, Pred, Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -803,9 +803,8 @@ 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(symVal.getAsRegion())) { - QualType ObjTy = CNE->getType()->getAs()->getPointeeType(); + if (const auto *NewReg = cast_or_null(symVal.getAsRegion())) { + QualType ObjTy = CNE->getType()->getPointeeType(); const ElementRegion *EleReg = getStoreManager().GetElementZeroRegion(NewReg, ObjTy); Result = loc::MemRegionVal(EleReg); Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1075,7 +1075,7 @@ const SubRegion *Super, bool IsVirtual) { if (isa(Super)) { - assert(isValidBaseClass(RD, dyn_cast(Super), IsVirtual)); + assert(isValidBaseClass(RD, cast(Super), IsVirtual)); (void)&isValidBaseClass; if (IsVirtual) { @@ -1426,6 +1426,7 @@ case MemRegion::FieldRegionKind: { const auto *FR = cast(R); R = FR->getSuperRegion(); + assert(R); const RecordDecl *RD = FR->getDecl()->getParent(); if (RD->isUnion() || !RD->isCompleteDefinition()) { Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -2249,8 +2249,7 @@ const TypedValueRegion* R, SVal V) { QualType T = R->getValueType(); - assert(T->isVectorType()); - const VectorType *VT = T->getAs(); // Use getAs for typedefs. + const VectorType *VT = T->castAs(); // Use castAs for typedefs. // Handle lazy compound values and symbolic values. if (V.getAs() || V.getAs()) @@ -2335,7 +2334,7 @@ QualType T = R->getValueType(); assert(T->isStructureOrClassType()); - const RecordType* RT = T->getAs(); + const RecordType* RT = T->castAs(); const RecordDecl *RD = RT->getDecl(); if (!RD->isCompleteDefinition()) Index: clang/test/Analysis/cstring-syntax-weird.c =================================================================== --- /dev/null +++ clang/test/Analysis/cstring-syntax-weird.c @@ -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 +} Index: clang/test/Analysis/cstring-syntax-weird2.c =================================================================== --- /dev/null +++ clang/test/Analysis/cstring-syntax-weird2.c @@ -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: clang/test/Analysis/cstring-syntax.c =================================================================== --- clang/test/Analysis/cstring-syntax.c +++ clang/test/Analysis/cstring-syntax.c @@ -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);