Author: henrywong Date: Wed Aug 22 06:30:46 2018 New Revision: 340407 URL: http://llvm.org/viewvc/llvm-project?rev=340407&view=rev Log: [analyzer] Improve `CallDescription` to handle c++ method.
Summary: `CallDecription` can only handle function for the time being. If we want to match c++ method, we can only use method name to match and can't improve the matching accuracy through the qualifiers. This patch add the support for `QualifiedName` matching to improve the matching accuracy. Reviewers: xazax.hun, NoQ, george.karpenkov, rnkovacs Reviewed By: xazax.hun, NoQ, rnkovacs Subscribers: Szelethus, szepet, rnkovacs, a.sidorin, mikhail.ramalho, cfe-commits, MTC Differential Revision: https://reviews.llvm.org/D48027 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=340407&r1=340406&r2=340407&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Wed Aug 22 06:30:46 2018 @@ -80,7 +80,9 @@ class CallDescription { mutable IdentifierInfo *II = nullptr; mutable bool IsLookupDone = false; - StringRef FuncName; + // The list of the qualified names used to identify the specified CallEvent, + // e.g. "{a, b}" represent the qualified names, like "a::b". + std::vector<StringRef> QualifiedName; unsigned RequiredArgs; public: @@ -88,16 +90,31 @@ public: /// Constructs a CallDescription object. /// + /// @param QualifiedName The list of the qualified names of the function that + /// will be matched. It does not require the user to provide the full list of + /// the qualified name. The more details provided, the more accurate the + /// matching. + /// + /// @param RequiredArgs The number of arguments that is expected to match a + /// call. Omit this parameter to match every occurrence of call with a given + /// name regardless the number of arguments. + CallDescription(std::vector<StringRef> QualifiedName, + unsigned RequiredArgs = NoArgRequirement) + : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {} + + /// Constructs a CallDescription object. + /// /// @param FuncName The name of the function that will be matched. /// /// @param RequiredArgs The number of arguments that is expected to match a /// call. Omit this parameter to match every occurrence of call with a given /// name regardless the number of arguments. CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement) - : FuncName(FuncName), RequiredArgs(RequiredArgs) {} + : CallDescription(std::vector<StringRef>({FuncName}), NoArgRequirement) { + } /// Get the name of the function that this object matches. - StringRef getFunctionName() const { return FuncName; } + StringRef getFunctionName() const { return QualifiedName.back(); } }; template<typename T = CallEvent> Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp?rev=340407&r1=340406&r2=340407&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Wed Aug 22 06:30:46 2018 @@ -86,14 +86,20 @@ public: }; InnerPointerChecker() - : AppendFn("append"), AssignFn("assign"), ClearFn("clear"), - CStrFn("c_str"), DataFn("data"), EraseFn("erase"), InsertFn("insert"), - PopBackFn("pop_back"), PushBackFn("push_back"), ReplaceFn("replace"), - ReserveFn("reserve"), ResizeFn("resize"), - ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {} - - /// Check if the object of this member function call is a `basic_string`. - bool isCalledOnStringObject(const CXXInstanceCall *ICall) const; + : AppendFn({"std", "basic_string", "append"}), + AssignFn({"std", "basic_string", "assign"}), + ClearFn({"std", "basic_string", "clear"}), + CStrFn({"std", "basic_string", "c_str"}), + DataFn({"std", "basic_string", "data"}), + EraseFn({"std", "basic_string", "erase"}), + InsertFn({"std", "basic_string", "insert"}), + PopBackFn({"std", "basic_string", "pop_back"}), + PushBackFn({"std", "basic_string", "push_back"}), + ReplaceFn({"std", "basic_string", "replace"}), + ReserveFn({"std", "basic_string", "reserve"}), + ResizeFn({"std", "basic_string", "resize"}), + ShrinkToFitFn({"std", "basic_string", "shrink_to_fit"}), + SwapFn({"std", "basic_string", "swap"}) {} /// Check whether the called member function potentially invalidates /// pointers referring to the container object's inner buffer. @@ -122,21 +128,6 @@ public: } // end anonymous namespace -bool InnerPointerChecker::isCalledOnStringObject( - const CXXInstanceCall *ICall) const { - const auto *ObjRegion = - dyn_cast_or_null<TypedValueRegion>(ICall->getCXXThisVal().getAsRegion()); - if (!ObjRegion) - return false; - - QualType ObjTy = ObjRegion->getValueType(); - if (ObjTy.isNull()) - return false; - - CXXRecordDecl *Decl = ObjTy->getAsCXXRecordDecl(); - return Decl && Decl->getName() == "basic_string"; -} - bool InnerPointerChecker::isInvalidatingMemberFunction( const CallEvent &Call) const { if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) { @@ -220,33 +211,31 @@ void InnerPointerChecker::checkPostCall( ProgramStateRef State = C.getState(); if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) { - if (isCalledOnStringObject(ICall)) { - const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>( - ICall->getCXXThisVal().getAsRegion()); - - if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { - SVal RawPtr = Call.getReturnValue(); - if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) { - // Start tracking this raw pointer by adding it to the set of symbols - // associated with this container object in the program state map. - - PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); - const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion); - PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet(); - assert(C.wasInlined || !Set.contains(Sym)); - Set = F.add(Set, Sym); - - State = State->set<RawPtrMap>(ObjRegion, Set); - C.addTransition(State); - } - return; - } + const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>( + ICall->getCXXThisVal().getAsRegion()); + + if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { + SVal RawPtr = Call.getReturnValue(); + if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) { + // Start tracking this raw pointer by adding it to the set of symbols + // associated with this container object in the program state map. + + PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); + const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion); + PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet(); + assert(C.wasInlined || !Set.contains(Sym)); + Set = F.add(Set, Sym); - // Check [string.require] / second point. - if (isInvalidatingMemberFunction(Call)) { - markPtrSymbolsReleased(Call, State, ObjRegion, C); - return; + State = State->set<RawPtrMap>(ObjRegion, Set); + C.addTransition(State); } + return; + } + + // Check [string.require] / second point. + if (isInvalidatingMemberFunction(Call)) { + markPtrSymbolsReleased(Call, State, ObjRegion, C); + return; } } Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=340407&r1=340406&r2=340407&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Wed Aug 22 06:30:46 2018 @@ -359,11 +359,38 @@ bool CallEvent::isCalled(const CallDescr return false; if (!CD.IsLookupDone) { CD.IsLookupDone = true; - CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + CD.II = &getState()->getStateManager().getContext().Idents.get( + CD.getFunctionName()); } const IdentifierInfo *II = getCalleeIdentifier(); if (!II || II != CD.II) return false; + + const Decl *D = getDecl(); + // If CallDescription provides prefix names, use them to improve matching + // accuracy. + if (CD.QualifiedName.size() > 1 && D) { + const DeclContext *Ctx = D->getDeclContext(); + std::vector<StringRef> QualifiedName = CD.QualifiedName; + QualifiedName.pop_back(); + for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) { + if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) { + if (!QualifiedName.empty() && ND->getName() == QualifiedName.back()) + QualifiedName.pop_back(); + continue; + } + + if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) { + if (!QualifiedName.empty() && RD->getName() == QualifiedName.back()) + QualifiedName.pop_back(); + continue; + } + } + + if (!QualifiedName.empty()) + return false; + } + return (CD.RequiredArgs == CallDescription::NoArgRequirement || CD.RequiredArgs == getNumArgs()); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits