Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ cfe/trunk/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,6 +1063,7 @@ // e.g. "{a, b}" represent the qualified names, like "a::b". std::vector QualifiedName; Optional RequiredArgs; + int Flags; public: /// Constructs a CallDescription object. @@ -1067,9 +1076,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 QualifiedName, + Optional RequiredArgs = None) + : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs), + Flags(Flags) {} + + /// Construct a CallDescription with default flags. CallDescription(ArrayRef QualifiedName, Optional RequiredArgs = None) - : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {} + : CallDescription(0, QualifiedName, RequiredArgs) {} /// Get the name of the function that this object matches. StringRef getFunctionName() const { return QualifiedName.back(); } Index: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -356,20 +356,32 @@ // 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(getDecl()); + if (!FD) + return false; + + if (CD.Flags & CDF_MaybeBuiltin) { + return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) && + (!CD.RequiredArgs || 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) + + if (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(Ctx); Ctx = Ctx->getParent()) { Index: cfe/trunk/unittests/StaticAnalyzer/CallDescriptionTest.cpp =================================================================== --- cfe/trunk/unittests/StaticAnalyzer/CallDescriptionTest.cpp +++ cfe/trunk/unittests/StaticAnalyzer/CallDescriptionTest.cpp @@ -143,6 +143,18 @@ {{{"bar", "foo"}}, false}, {{"foo"}, true}, }), "void foo(); struct bar { void foo(); }; void test() { foo(); }")); + + // Test CDF_MaybeBuiltin - a flag that allows matching weird builtins. + 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