diff options
-rw-r--r-- | include/clang/AST/Decl.h | 25 | ||||
-rw-r--r-- | include/clang/Basic/Builtins.def | 5 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 48 |
5 files changed, 67 insertions, 62 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 5c6b447f91..4016c2085f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1986,26 +1986,11 @@ public: /// definition of a member function. virtual bool isOutOfLine() const; - /// \brief Enumeration used to identify memory setting or copying functions - /// identified by getMemoryFunctionKind(). - enum MemoryFunctionKind { - MFK_Memset, - MFK_Memcpy, - MFK_Memmove, - MFK_Memcmp, - MFK_Strncpy, - MFK_Strncmp, - MFK_Strncasecmp, - MFK_Strncat, - MFK_Strndup, - MFK_Strlcpy, - MFK_Strlcat, - MFK_Invalid - }; - - /// \brief If the given function is a memory copy or setting function, return - /// it's kind. If the function is not a memory function, returns MFK_Invalid. - MemoryFunctionKind getMemoryFunctionKind(); + /// \brief Identify a memory copying or setting function. + /// If the given function is a memory copy or setting function, returns + /// the corresponding Builtin ID. If the function is not a memory function, + /// returns 0. + unsigned getMemoryFunctionKind(); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 5942e53eaf..e3e2d7c26b 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -631,9 +631,12 @@ LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES) LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES) // C99 string.h LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncmp, "icC*cC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) @@ -678,6 +681,8 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES) // POSIX unistd.h LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES) LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c4af62530a..242af88c89 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6315,7 +6315,7 @@ private: bool isPrintf); void CheckMemaccessArguments(const CallExpr *Call, - FunctionDecl::MemoryFunctionKind CMF, + unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 96766dca5b..195136313b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2290,80 +2290,83 @@ SourceRange FunctionDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), EndRangeLoc); } -FunctionDecl::MemoryFunctionKind FunctionDecl::getMemoryFunctionKind() { +unsigned FunctionDecl::getMemoryFunctionKind() { IdentifierInfo *FnInfo = getIdentifier(); if (!FnInfo) - return MFK_Invalid; + return 0; // Builtin handling. switch (getBuiltinID()) { case Builtin::BI__builtin_memset: case Builtin::BI__builtin___memset_chk: case Builtin::BImemset: - return MFK_Memset; + return Builtin::BImemset; case Builtin::BI__builtin_memcpy: case Builtin::BI__builtin___memcpy_chk: case Builtin::BImemcpy: - return MFK_Memcpy; + return Builtin::BImemcpy; case Builtin::BI__builtin_memmove: case Builtin::BI__builtin___memmove_chk: case Builtin::BImemmove: - return MFK_Memmove; + return Builtin::BImemmove; case Builtin::BIstrlcpy: - return MFK_Strlcpy; + return Builtin::BIstrlcpy; case Builtin::BIstrlcat: - return MFK_Strlcat; + return Builtin::BIstrlcat; case Builtin::BI__builtin_memcmp: - return MFK_Memcmp; + case Builtin::BImemcmp: + return Builtin::BImemcmp; case Builtin::BI__builtin_strncpy: case Builtin::BI__builtin___strncpy_chk: case Builtin::BIstrncpy: - return MFK_Strncpy; + return Builtin::BIstrncpy; case Builtin::BI__builtin_strncmp: - return MFK_Strncmp; + case Builtin::BIstrncmp: + return Builtin::BIstrncmp; case Builtin::BI__builtin_strncasecmp: - return MFK_Strncasecmp; + case Builtin::BIstrncasecmp: + return Builtin::BIstrncasecmp; case Builtin::BI__builtin_strncat: case Builtin::BIstrncat: - return MFK_Strncat; + return Builtin::BIstrncat; case Builtin::BI__builtin_strndup: case Builtin::BIstrndup: - return MFK_Strndup; + return Builtin::BIstrndup; default: if (isExternC()) { if (FnInfo->isStr("memset")) - return MFK_Memset; + return Builtin::BImemset; else if (FnInfo->isStr("memcpy")) - return MFK_Memcpy; + return Builtin::BImemcpy; else if (FnInfo->isStr("memmove")) - return MFK_Memmove; + return Builtin::BImemmove; else if (FnInfo->isStr("memcmp")) - return MFK_Memcmp; + return Builtin::BImemcmp; else if (FnInfo->isStr("strncpy")) - return MFK_Strncpy; + return Builtin::BIstrncpy; else if (FnInfo->isStr("strncmp")) - return MFK_Strncmp; + return Builtin::BIstrncmp; else if (FnInfo->isStr("strncasecmp")) - return MFK_Strncasecmp; + return Builtin::BIstrncasecmp; else if (FnInfo->isStr("strncat")) - return MFK_Strncat; + return Builtin::BIstrncat; else if (FnInfo->isStr("strndup")) - return MFK_Strndup; + return Builtin::BIstrndup; } break; } - return MFK_Invalid; + return 0; } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 77c5717d24..af0eedd791 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -482,15 +482,15 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } - FunctionDecl::MemoryFunctionKind CMF = FDecl->getMemoryFunctionKind(); - if (CMF == FunctionDecl::MFK_Invalid) + unsigned CMId = FDecl->getMemoryFunctionKind(); + if (CMId == 0) return false; // Handle memory setting and copying functions. - if (CMF == FunctionDecl::MFK_Strlcpy || CMF == FunctionDecl::MFK_Strlcat) + if (CMId == Builtin::BIstrlcpy || CMId == Builtin::BIstrlcat) CheckStrlcpycatArguments(TheCall, FnInfo); else - CheckMemaccessArguments(TheCall, CMF, FnInfo); + CheckMemaccessArguments(TheCall, CMId, FnInfo); return false; } @@ -2433,17 +2433,19 @@ static QualType getSizeOfArgType(const Expr* E) { /// /// \param Call The call expression to diagnose. void Sema::CheckMemaccessArguments(const CallExpr *Call, - FunctionDecl::MemoryFunctionKind CMF, + unsigned BId, IdentifierInfo *FnName) { + assert(BId != 0); + // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - unsigned ExpectedNumArgs = (CMF == FunctionDecl::MFK_Strndup ? 2 : 3); + unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3); if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (CMF == FunctionDecl::MFK_Memset || - CMF == FunctionDecl::MFK_Strndup ? 1 : 2); - unsigned LenArg = (CMF == FunctionDecl::MFK_Strndup ? 1 : 2); + unsigned LastArg = (BId == Builtin::BImemset || + BId == Builtin::BIstrndup ? 1 : 2); + unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2); const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); // We have special checking when the length is a sizeof expression. @@ -2488,7 +2490,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, ActionIdx = 2; // If the pointee's size is sizeof(char), // suggest an explicit length. unsigned DestSrcSelect = - (CMF == FunctionDecl::MFK_Strndup ? 1 : ArgIdx); + (BId == Builtin::BIstrndup ? 1 : ArgIdx); DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest, PDiag(diag::warn_sizeof_pointer_expr_memaccess) << FnName << DestSrcSelect << ActionIdx @@ -2514,19 +2516,29 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, } // Always complain about dynamic classes. - if (isDynamicClassType(PointeeTy)) + if (isDynamicClassType(PointeeTy)) { + + unsigned OperationType = 0; + // "overwritten" if we're warning about the destination for any call + // but memcmp; otherwise a verb appropriate to the call. + if (ArgIdx != 0 || BId == Builtin::BImemcmp) { + if (BId == Builtin::BImemcpy) + OperationType = 1; + else if(BId == Builtin::BImemmove) + OperationType = 2; + else if (BId == Builtin::BImemcmp) + OperationType = 3; + } + DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_dyn_class_memaccess) - << (CMF == FunctionDecl::MFK_Memcmp ? ArgIdx + 2 : ArgIdx) + << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy - // "overwritten" if we're warning about the destination for any call - // but memcmp; otherwise a verb appropriate to the call. - << (ArgIdx == 0 && - CMF != FunctionDecl::MFK_Memcmp ? 0 : (unsigned)CMF) + << OperationType << Call->getCallee()->getSourceRange()); - else if (PointeeTy.hasNonTrivialObjCLifetime() && - CMF != FunctionDecl::MFK_Memset) + } else if (PointeeTy.hasNonTrivialObjCLifetime() && + BId != Builtin::BImemset) DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_arc_object_memaccess) |