diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp | 130 |
1 files changed, 63 insertions, 67 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp index ad1a89e71bf..c2f4b053fdd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp @@ -72,6 +72,27 @@ public: void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; }; +/// A basic field type, that is not a pointer or a reference, it's dynamic and +/// static type is the same. +class RegularField : public FieldNode { +public: + RegularField(const FieldRegion *FR) : FieldNode(FR) {} + + virtual void printNoteMsg(llvm::raw_ostream &Out) const override { + Out << "uninitialized field "; + } + + virtual void printPrefix(llvm::raw_ostream &Out) const override {} + + virtual void printNode(llvm::raw_ostream &Out) const { + Out << getVariableName(getDecl()); + } + + virtual void printSeparator(llvm::raw_ostream &Out) const override { + Out << '.'; + } +}; + } // end of anonymous namespace // Utility function declarations. @@ -89,14 +110,6 @@ getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context); static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context); -/// Constructs a note message for a given FieldChainInfo object. -static void printNoteMessage(llvm::raw_ostream &Out, - const FieldChainInfo &Chain); - -/// Returns with Field's name. This is a helper function to get the correct name -/// even if Field is a captured lambda variable. -static StringRef getVariableName(const FieldDecl *Field); - //===----------------------------------------------------------------------===// // Methods for UninitializedObjectChecker. //===----------------------------------------------------------------------===// @@ -126,7 +139,7 @@ void UninitializedObjectChecker::checkEndFunction( FindUninitializedFields F(Context.getState(), Object->getRegion(), IsPedantic, CheckPointeeInitialization); - const UninitFieldSet &UninitFields = F.getUninitFields(); + const UninitFieldMap &UninitFields = F.getUninitFields(); if (UninitFields.empty()) return; @@ -146,14 +159,10 @@ void UninitializedObjectChecker::checkEndFunction( // For Plist consumers that don't support notes just yet, we'll convert notes // to warnings. if (ShouldConvertNotesToWarnings) { - for (const auto &Chain : UninitFields) { - SmallString<100> WarningBuf; - llvm::raw_svector_ostream WarningOS(WarningBuf); - - printNoteMessage(WarningOS, Chain); + for (const auto &Pair : UninitFields) { auto Report = llvm::make_unique<BugReport>( - *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, + *BT_uninitField, Pair.second, Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); Context.emitReport(std::move(Report)); } @@ -170,14 +179,9 @@ void UninitializedObjectChecker::checkEndFunction( *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); - for (const auto &Chain : UninitFields) { - SmallString<200> NoteBuf; - llvm::raw_svector_ostream NoteOS(NoteBuf); - - printNoteMessage(NoteOS, Chain); - - Report->addNote(NoteOS.str(), - PathDiagnosticLocation::create(Chain.getEndOfChain(), + for (const auto &Pair : UninitFields) { + Report->addNote(Pair.second, + PathDiagnosticLocation::create(Pair.first->getDecl(), Context.getSourceManager())); } Context.emitReport(std::move(Report)); @@ -193,8 +197,8 @@ FindUninitializedFields::FindUninitializedFields( : State(State), ObjectR(R), IsPedantic(IsPedantic), CheckPointeeInitialization(CheckPointeeInitialization) {} -const UninitFieldSet &FindUninitializedFields::getUninitFields() { - isNonUnionUninit(ObjectR, FieldChainInfo(Factory)); +const UninitFieldMap &FindUninitializedFields::getUninitFields() { + isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory)); if (!IsPedantic && !IsAnyFieldInitialized) UninitFields.clear(); @@ -204,10 +208,15 @@ const UninitFieldSet &FindUninitializedFields::getUninitFields() { bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) { if (State->getStateManager().getContext().getSourceManager().isInSystemHeader( - Chain.getEndOfChain()->getLocation())) + Chain.getUninitRegion()->getDecl()->getLocation())) return false; - return UninitFields.insert(Chain).second; + UninitFieldMap::mapped_type NoteMsgBuf; + llvm::raw_svector_ostream OS(NoteMsgBuf); + Chain.printNoteMsg(OS); + return UninitFields + .insert(std::make_pair(Chain.getUninitRegion(), std::move(NoteMsgBuf))) + .second; } bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R, @@ -237,14 +246,14 @@ bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R, return false; if (T->isStructureOrClassType()) { - if (isNonUnionUninit(FR, {LocalChain, FR})) + if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR)))) ContainsUninitField = true; continue; } if (T->isUnionType()) { if (isUnionUninit(FR)) { - if (addFieldToUninits({LocalChain, FR})) + if (addFieldToUninits(LocalChain.add(RegularField(FR)))) ContainsUninitField = true; } else IsAnyFieldInitialized = true; @@ -266,7 +275,7 @@ bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R, SVal V = State->getSVal(FieldVal); if (isPrimitiveUninit(V)) { - if (addFieldToUninits({LocalChain, FR})) + if (addFieldToUninits(LocalChain.add(RegularField(FR)))) ContainsUninitField = true; } continue; @@ -323,27 +332,17 @@ bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) { // Methods for FieldChainInfo. //===----------------------------------------------------------------------===// -FieldChainInfo::FieldChainInfo(const FieldChainInfo &Other, - const FieldRegion *FR, const bool IsDereferenced) - : FieldChainInfo(Other, IsDereferenced) { - assert(!contains(FR) && "Can't add a field that is already a part of the " - "fieldchain! Is this a cyclic reference?"); - Chain = Factory.add(FR, Other.Chain); -} - -bool FieldChainInfo::isPointer() const { +const FieldRegion *FieldChainInfo::getUninitRegion() const { assert(!Chain.isEmpty() && "Empty fieldchain!"); - return (*Chain.begin())->getDecl()->getType()->isPointerType(); -} - -bool FieldChainInfo::isDereferenced() const { - assert(isPointer() && "Only pointers may or may not be dereferenced!"); - return IsDereferenced; + return (*Chain.begin()).getRegion(); } -const FieldDecl *FieldChainInfo::getEndOfChain() const { - assert(!Chain.isEmpty() && "Empty fieldchain!"); - return (*Chain.begin())->getDecl(); +bool FieldChainInfo::contains(const FieldRegion *FR) const { + for (const FieldNode &Node : Chain) { + if (Node.isSameRegion(FR)) + return true; + } + return false; } /// Prints every element except the last to `Out`. Since ImmutableLists store @@ -386,13 +385,23 @@ static void printTail(llvm::raw_ostream &Out, // "uninitialized field 'this->x'", but we can't refer to 'x' directly, // we need an explicit namespace resolution whether the uninit field was // 'D1::x' or 'D2::x'. -void FieldChainInfo::print(llvm::raw_ostream &Out) const { +void FieldChainInfo::printNoteMsg(llvm::raw_ostream &Out) const { if (Chain.isEmpty()) return; const FieldChainImpl *L = Chain.getInternalPointer(); + const FieldNode &LastField = L->getHead(); + + LastField.printNoteMsg(Out); + Out << '\''; + + for (const FieldNode &Node : Chain) + Node.printPrefix(Out); + + Out << "this->"; printTail(Out, L->getTail()); - Out << getVariableName(L->getHead()->getDecl()); + LastField.printNode(Out); + Out << '\''; } static void printTail(llvm::raw_ostream &Out, @@ -401,9 +410,9 @@ static void printTail(llvm::raw_ostream &Out, return; printTail(Out, L->getTail()); - const FieldDecl *Field = L->getHead()->getDecl(); - Out << getVariableName(Field); - Out << (Field->getType()->isPointerType() ? "->" : "."); + + L->getHead().printNode(Out); + L->getHead().printSeparator(Out); } //===----------------------------------------------------------------------===// @@ -453,20 +462,7 @@ static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, return false; } -static void printNoteMessage(llvm::raw_ostream &Out, - const FieldChainInfo &Chain) { - if (Chain.isPointer()) { - if (Chain.isDereferenced()) - Out << "uninitialized pointee 'this->"; - else - Out << "uninitialized pointer 'this->"; - } else - Out << "uninitialized field 'this->"; - Chain.print(Out); - Out << "'"; -} - -static StringRef getVariableName(const FieldDecl *Field) { +StringRef clang::ento::getVariableName(const FieldDecl *Field) { // If Field is a captured lambda variable, Field->getName() will return with // an empty string. We can however acquire it's name from the lambda's // captures. |