diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer')
3 files changed, 92 insertions, 140 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 88feb6a..e682c4e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -99,7 +99,7 @@ class NilArgChecker : public Checker<check::PreObjCMessage, check::PostStmt<ObjCDictionaryLiteral>, check::PostStmt<ObjCArrayLiteral>, EventDispatcher<ImplicitNullDerefEvent>> { - mutable std::unique_ptr<APIMisuse> BT; + const APIMisuse BT{this, "nil argument"}; mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors; mutable Selector ArrayWithObjectSel; @@ -218,10 +218,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N, SourceRange Range, const Expr *E, CheckerContext &C) const { - if (!BT) - BT.reset(new APIMisuse(this, "nil argument")); - - auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N); + auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N); R->addRange(Range); bugreporter::trackExpressionValue(N, E, *R); C.emitReport(std::move(R)); @@ -350,7 +347,7 @@ void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, namespace { class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > { - mutable std::unique_ptr<APIMisuse> BT; + const APIMisuse BT{this, "Bad use of CFNumber APIs"}; mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr; public: CFNumberChecker() = default; @@ -524,10 +521,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, << " bits of the integer value will be " << (isCreate ? "lost." : "garbage."); - if (!BT) - BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs")); - - auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N); + auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); C.emitReport(std::move(report)); } @@ -539,7 +533,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, namespace { class CFRetainReleaseChecker : public Checker<check::PreCall> { - mutable APIMisuse BT{this, "null passed to CF memory management function"}; + const APIMisuse BT{this, "null passed to CF memory management function"}; const CallDescriptionSet ModelledCalls = { {CDM::CLibrary, {"CFRetain"}, 1}, {CDM::CLibrary, {"CFRelease"}, 1}, @@ -600,7 +594,8 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> { mutable Selector retainS; mutable Selector autoreleaseS; mutable Selector drainS; - mutable std::unique_ptr<BugType> BT; + const APIMisuse BT{ + this, "message incorrectly sent to class instead of class instance"}; public: void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; @@ -609,10 +604,7 @@ public: void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { - if (!BT) { - BT.reset(new APIMisuse( - this, "message incorrectly sent to class instead of class instance")); - + if (releaseS.isNull()) { ASTContext &Ctx = C.getASTContext(); releaseS = GetNullarySelector("release", Ctx); retainS = GetNullarySelector("retain", Ctx); @@ -639,7 +631,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, "of class '" << Class->getName() << "' and not the class directly"; - auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N); + auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N); report->addRange(msg.getSourceRange()); C.emitReport(std::move(report)); } @@ -658,7 +650,8 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { mutable Selector orderedSetWithObjectsS; mutable Selector initWithObjectsS; mutable Selector initWithObjectsAndKeysS; - mutable std::unique_ptr<BugType> BT; + const APIMisuse BT{this, "Arguments passed to variadic method aren't all " + "Objective-C pointer types"}; bool isVariadicMessage(const ObjCMethodCall &msg) const; @@ -717,11 +710,7 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { - if (!BT) { - BT.reset(new APIMisuse(this, - "Arguments passed to variadic method aren't all " - "Objective-C pointer types")); - + if (arrayWithObjectsS.isNull()) { ASTContext &Ctx = C.getASTContext(); arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); dictionaryWithObjectsAndKeysS = @@ -792,8 +781,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, ArgTy.print(os, C.getLangOpts()); os << "'"; - auto R = - std::make_unique<PathSensitiveBugReport>(*BT, os.str(), *errorNode); + auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), *errorNode); R->addRange(msg.getArgSourceRange(I)); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index d7eea7e..152129e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -25,18 +25,22 @@ using namespace clang; using namespace ento; namespace { + +class DerefBugType : public BugType { + StringRef ArrayMsg, FieldMsg; + +public: + DerefBugType(CheckerFrontend *FE, StringRef Desc, const char *AMsg, + const char *FMsg = nullptr) + : BugType(FE, Desc), ArrayMsg(AMsg), FieldMsg(FMsg ? FMsg : AMsg) {} + StringRef getArrayMsg() const { return ArrayMsg; } + StringRef getFieldMsg() const { return FieldMsg; } +}; + class DereferenceChecker - : public Checker< check::Location, - check::Bind, - EventDispatcher<ImplicitNullDerefEvent> > { - enum DerefKind { - NullPointer, - UndefinedPointerValue, - AddressOfLabel, - FixedAddress, - }; - - void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, + : public CheckerFamily<check::Location, check::Bind, + EventDispatcher<ImplicitNullDerefEvent>> { + void reportBug(const DerefBugType &BT, ProgramStateRef State, const Stmt *S, CheckerContext &C) const; bool suppressReport(CheckerContext &C, const Expr *E) const; @@ -52,13 +56,23 @@ public: const LocationContext *LCtx, bool loadedFrom = false); - bool CheckNullDereference = false; - bool CheckFixedDereference = false; - - std::unique_ptr<BugType> BT_Null; - std::unique_ptr<BugType> BT_Undef; - std::unique_ptr<BugType> BT_Label; - std::unique_ptr<BugType> BT_FixedAddress; + CheckerFrontend NullDerefChecker, FixedDerefChecker; + const DerefBugType NullBug{&NullDerefChecker, "Dereference of null pointer", + "a null pointer dereference", + "a dereference of a null pointer"}; + const DerefBugType UndefBug{&NullDerefChecker, + "Dereference of undefined pointer value", + "an undefined pointer dereference", + "a dereference of an undefined pointer value"}; + const DerefBugType LabelBug{&NullDerefChecker, + "Dereference of the address of a label", + "an undefined pointer dereference", + "a dereference of an address of a label"}; + const DerefBugType FixedAddressBug{&FixedDerefChecker, + "Dereference of a fixed address", + "a dereference of a fixed address"}; + + StringRef getDebugTag() const override { return "DereferenceChecker"; } }; } // end anonymous namespace @@ -158,115 +172,87 @@ static bool isDeclRefExprToReference(const Expr *E) { return false; } -void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, - const Stmt *S, CheckerContext &C) const { - const BugType *BT = nullptr; - llvm::StringRef DerefStr1; - llvm::StringRef DerefStr2; - switch (K) { - case DerefKind::NullPointer: - if (!CheckNullDereference) { - C.addSink(); - return; - } - BT = BT_Null.get(); - DerefStr1 = " results in a null pointer dereference"; - DerefStr2 = " results in a dereference of a null pointer"; - break; - case DerefKind::UndefinedPointerValue: - if (!CheckNullDereference) { - C.addSink(); +void DereferenceChecker::reportBug(const DerefBugType &BT, + ProgramStateRef State, const Stmt *S, + CheckerContext &C) const { + if (&BT == &FixedAddressBug) { + if (!FixedDerefChecker.isEnabled()) + // Deliberately don't add a sink node if check is disabled. + // This situation may be valid in special cases. return; - } - BT = BT_Undef.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an undefined pointer value"; - break; - case DerefKind::AddressOfLabel: - if (!CheckNullDereference) { + } else { + if (!NullDerefChecker.isEnabled()) { C.addSink(); return; } - BT = BT_Label.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an address of a label"; - break; - case DerefKind::FixedAddress: - // Deliberately don't add a sink node if check is disabled. - // This situation may be valid in special cases. - if (!CheckFixedDereference) - return; - - BT = BT_FixedAddress.get(); - DerefStr1 = " results in a dereference of a fixed address"; - DerefStr2 = " results in a dereference of a fixed address"; - break; - }; + } // Generate an error node. ExplodedNode *N = C.generateErrorNode(State); if (!N) return; - SmallString<100> buf; - llvm::raw_svector_ostream os(buf); + SmallString<100> Buf; + llvm::raw_svector_ostream Out(Buf); SmallVector<SourceRange, 2> Ranges; switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::ArraySectionExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySectionExpr *AE = cast<ArraySectionExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::UnaryOperatorClass: { - os << BT->getDescription(); + Out << BT.getDescription(); const UnaryOperator *U = cast<UnaryOperator>(S); - AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), - State.get(), N->getLocationContext(), true); + AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(), + N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); if (M->isArrow() || isDeclRefExprToReference(M->getBase())) { - os << "Access to field '" << M->getMemberNameInfo() << "'" << DerefStr2; - AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to field '" << M->getMemberNameInfo() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); - os << "Access to instance variable '" << *IV->getDecl() << "'" << DerefStr2; - AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to instance variable '" << *IV->getDecl() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); break; } default: break; } - auto report = std::make_unique<PathSensitiveBugReport>( - *BT, buf.empty() ? BT->getDescription() : buf.str(), N); + auto BR = std::make_unique<PathSensitiveBugReport>( + BT, Buf.empty() ? BT.getDescription() : Buf.str(), N); - bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report); + bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *BR); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) - report->addRange(*I); + BR->addRange(*I); - C.emitReport(std::move(report)); + C.emitReport(std::move(BR)); } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -275,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (l.isUndef()) { const Expr *DerefExpr = getDereferenceExpr(S); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C); + reportBug(UndefBug, C.getState(), DerefExpr, C); return; } @@ -296,7 +282,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, // we call an "explicit" null dereference. const Expr *expr = getDereferenceExpr(S); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, nullState, expr, C); + reportBug(NullBug, nullState, expr, C); return; } } @@ -314,7 +300,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (location.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, isLoad); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C); + reportBug(FixedAddressBug, notNullState, DerefExpr, C); return; } @@ -330,7 +316,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, // One should never write to label addresses. if (auto Label = L.getAs<loc::GotoLabel>()) { - reportBug(DerefKind::AddressOfLabel, C.getState(), S, C); + reportBug(LabelBug, C.getState(), S, C); return; } @@ -351,7 +337,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (!StNonNull) { const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, StNull, expr, C); + reportBug(NullBug, StNull, expr, C); return; } } @@ -369,7 +355,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (V.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, true); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, State, DerefExpr, C); + reportBug(FixedAddressBug, State, DerefExpr, C); return; } @@ -392,26 +378,8 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, C.addTransition(State, this); } -void ento::registerDereferenceModeling(CheckerManager &Mgr) { - Mgr.registerChecker<DereferenceChecker>(); -} - -bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) { - return true; -} - void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckNullDereference = true; - Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of null pointer", - categories::LogicError)); - Chk->BT_Undef.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of undefined pointer value", - categories::LogicError)); - Chk->BT_Label.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of the address of a label", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr); } bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { @@ -419,11 +387,7 @@ bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { } void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckFixedDereference = true; - Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of a fixed address", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr); } bool ento::shouldRegisterFixedAddressDereferenceChecker( diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a7704da..369d619 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -2693,7 +2693,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range, Frontend->UseFreeBug, AF.Kind == AF_InnerBuffer ? "Inner pointer of container used after re/deallocation" - : "Use of memory after it is freed", + : "Use of memory after it is released", N); R->markInteresting(Sym); @@ -2721,8 +2721,8 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range, if (ExplodedNode *N = C.generateErrorNode()) { auto R = std::make_unique<PathSensitiveBugReport>( Frontend->DoubleFreeBug, - (Released ? "Attempt to free released memory" - : "Attempt to free non-owned memory"), + (Released ? "Attempt to release already released memory" + : "Attempt to release non-owned memory"), N); if (Range.isValid()) R->addRange(Range); |