r340407 - [analyzer] Improve `CallDescription` to handle c++ method.

Henry Wong via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 22 06:30:46 PDT 2018


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());
 }




More information about the cfe-commits mailing list