NoQ created this revision.
NoQ added reviewers: dcoughlin, xazax.hun, a_sidorin, rnkovacs, 
mikhail.ramalho, Szelethus, baloghadamsoftware, Charusso.
Herald added subscribers: cfe-commits, dkrupp, donat.nagy, a.sidorin, szepet.
Herald added a project: clang.
NoQ added a parent revision: D62441: [analyzer] NFC: Introduce a convenient 
CallDescriptionMap class..

When matching C standard library functions in the checker, it's easy to forget 
that they are often implemented as macros that are expanded to compiler 
builtins. Such builtins would have a different name, so matching the callee 
identifier would fail, or may sometimes have more arguments than expected (so 
matching the exact number of arguments would fail, but this is fine as long as 
we have all the arguments that we need in their respective places.

This patch adds a set of flags to the `CallDescription` class so that to handle 
various special matching rules, and adds the first flag into this set, which 
enables a more fuzzy matching for functions that may be implemented as builtins.


Repository:
  rC Clang

https://reviews.llvm.org/D62556

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp

Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
===================================================================
--- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
+++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -102,6 +102,16 @@
           {{"foo"}, true},
       }), "void foo(); struct bar { void foo(); }; void test() { foo(); }"));
 
+  EXPECT_TRUE(tooling::runToolOnCode(
+      new CallDescriptionAction({
+          {{"memset", 3}, false},
+          {{CDF_MaybeBuiltin, "memset", 3}, true}
+      }),
+      "void foo() {"
+      "  int x;"
+      "  __builtin___memset_chk(&x, 0, sizeof(x),"
+      "                         __builtin_object_size(&x, 0));"
+      "}"));
 }
 
 } // namespace
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -356,20 +356,33 @@
   // FIXME: Add ObjC Message support.
   if (getKind() == CE_ObjCMessage)
     return false;
+
+  const IdentifierInfo *II = getCalleeIdentifier();
+  if (!II)
+    return false;
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
+  if (!FD)
+    return false;
+
+  if (CD.Flags & CDF_MaybeBuiltin) {
+    return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) &&
+           (CD.RequiredArgs == CallDescription::NoArgRequirement ||
+            CD.RequiredArgs <= getNumArgs());
+  }
+
   if (!CD.IsLookupDone) {
     CD.IsLookupDone = true;
     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();
+  if (CD.QualifiedName.size() > 1 && FD) {
+    const DeclContext *Ctx = FD->getDeclContext();
     // See if we'll be able to match them all.
     size_t NumUnmatched = CD.QualifiedName.size() - 1;
     for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -1044,6 +1044,14 @@
   }
 };
 
+enum CallDescriptionFlags : int {
+  /// Describes a C standard function that is sometimes implemented as a macro
+  /// that expands to a compiler builtin with some __builtin prefix.
+  /// The builtin may as well have a few extra arguments on top of the requested
+  /// number of arguments.
+  CDF_MaybeBuiltin = 1 << 0,
+};
+
 /// This class represents a description of a function call using the number of
 /// arguments and the name of the function.
 class CallDescription {
@@ -1055,11 +1063,14 @@
   // e.g. "{a, b}" represent the qualified names, like "a::b".
   std::vector<const char *> QualifiedName;
   unsigned RequiredArgs;
+  int Flags;
 
 public:
   const static unsigned NoArgRequirement = std::numeric_limits<unsigned>::max();
 
   /// Constructs a CallDescription object.
+  /// @param Flags A bitwise-or of CallDescriptionFlags that tweak
+  /// the matching behavior of the CallDescription object.
   ///
   /// @param QualifiedName The list of the name qualifiers of the function that
   /// will be matched. The user is allowed to skip any of the qualifiers.
@@ -1069,9 +1080,15 @@
   /// @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(int Flags, ArrayRef<const char *> QualifiedName,
+                  unsigned RequiredArgs = NoArgRequirement)
+      : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
+        Flags(Flags) {}
+
+  /// Construct a CallDescription with default flags.
   CallDescription(ArrayRef<const char *> QualifiedName,
                   unsigned RequiredArgs = NoArgRequirement)
-      : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {}
+      : CallDescription(0, QualifiedName, RequiredArgs) {}
 
   /// Get the name of the function that this object matches.
   StringRef getFunctionName() const { return QualifiedName.back(); }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to