summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2013-12-26 23:38:39 +0000
committerNico Weber <nicolasweber@gmx.de>2013-12-26 23:38:39 +0000
commit0e6daefe8f11c7a0e82c5b1455a0ff1d89a986bd (patch)
tree12c00afd7339e39cb79c438eb1cccb3ed4c7d772 /clang/lib/Sema/SemaChecking.cpp
parent63701d2533005555c485569553079f6122430d24 (diff)
downloadbcm5719-llvm-0e6daefe8f11c7a0e82c5b1455a0ff1d89a986bd.tar.gz
bcm5719-llvm-0e6daefe8f11c7a0e82c5b1455a0ff1d89a986bd.zip
Warn on mismatched parentheses in memcmp and friends.
Thisadds a new warning that warns on code like this: if (memcmp(a, b, sizeof(a) != 0)) The warning looks like: test4.cc:5:30: warning: size argument in 'memcmp' call is a comparison [-Wmemsize-comparison] if (memcmp(a, b, sizeof(a) != 0)) ~~~~~~~~~~^~~~ test4.cc:5:7: note: did you mean to compare the result of 'memcmp' instead? if (memcmp(a, b, sizeof(a) != 0)) ^ ~ ) test4.cc:5:20: note: explicitly cast the argument to size_t to silence this warning if (memcmp(a, b, sizeof(a) != 0)) ^ (size_t)( ) 1 warning generated. This found 2 bugs in chromium and has 0 false positives on both chromium and llvm. The idea of triggering this warning on a binop in the size argument is due to rnk. llvm-svn: 198063
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp50
1 files changed, 48 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 97c041c9013..feee61ea5ec 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -622,7 +622,7 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
RHS.get(), AA_Assigning))
return true;
}
-
+
// For NEON intrinsics which take an immediate value as part of the
// instruction, range check them here.
unsigned i = 0, l = 0, u = 0;
@@ -3560,6 +3560,40 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
//===--- CHECK: Standard memory functions ---------------------------------===//
+/// \brief Takes the expression passed to the size_t parameter of functions
+/// such as memcmp, strncat, etc and warns if it's a comparison.
+///
+/// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`.
+static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
+ IdentifierInfo *FnName,
+ SourceLocation FnLoc,
+ SourceLocation RParenLoc) {
+ const BinaryOperator *Size = dyn_cast<BinaryOperator>(E);
+ if (!Size)
+ return false;
+
+ // if E is binop and op is >, <, >=, <=, ==, &&, ||:
+ if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp())
+ return false;
+
+ Preprocessor &PP = S.getPreprocessor();
+ SourceRange SizeRange = Size->getSourceRange();
+ S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison)
+ << SizeRange << FnName;
+ S.Diag(FnLoc, diag::warn_memsize_comparison_paren_note)
+ << FnName
+ << FixItHint::CreateInsertion(
+ PP.getLocForEndOfToken(Size->getLHS()->getLocEnd()),
+ ")")
+ << FixItHint::CreateRemoval(RParenLoc);
+ S.Diag(SizeRange.getBegin(), diag::warn_memsize_comparison_cast_note)
+ << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(")
+ << FixItHint::CreateInsertion(
+ PP.getLocForEndOfToken(SizeRange.getEnd()), ")");
+
+ return true;
+}
+
/// \brief Determine whether the given type is a dynamic class type (e.g.,
/// whether it has a vtable).
static bool isDynamicClassType(QualType T) {
@@ -3615,6 +3649,10 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
+ if (CheckMemorySizeofForComparison(*this, LenExpr, FnName,
+ Call->getLocStart(), Call->getRParenLoc()))
+ return;
+
// We have special checking when the length is a sizeof expression.
QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
@@ -3798,6 +3836,10 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context);
const Expr *CompareWithSrc = NULL;
+
+ if (CheckMemorySizeofForComparison(*this, SizeArg, FnName,
+ Call->getLocStart(), Call->getRParenLoc()))
+ return;
// Look for 'strlcpy(dst, x, sizeof(x))'
if (const Expr *Ex = getSizeOfExprArg(SizeArg))
@@ -3880,6 +3922,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts();
const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts();
+ if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getLocStart(),
+ CE->getRParenLoc()))
+ return;
+
// Identify common expressions, which are wrongly used as the size argument
// to strncat and may lead to buffer overflows.
unsigned PatternType = 0;
@@ -5235,7 +5281,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (Target->isSpecificBuiltinType(BuiltinType::Bool)) {
if (isa<StringLiteral>(E))
// Warn on string literal to bool. Checks for string literals in logical
- // expressions, for instances, assert(0 && "error here"), is prevented
+ // expressions, for instances, assert(0 && "error here"), are prevented
// by a check in AnalyzeImplicitConversions().
return DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_string_literal_to_bool);
OpenPOWER on IntegriCloud