aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2011-04-27 07:05:31 +0000
committerChandler Carruth <chandlerc@gmail.com>2011-04-27 07:05:31 +0000
commit7ccc95bceebb2d1c8fbe277c9e33bde7dc1ccbb1 (patch)
treea0ee5fcc77c93f3b704f7c4b821c800af8573118
parentd46a1125d43bcfd47fbd1206ebd1226863549390 (diff)
Add a warning (-Wnon-pod-memset) for calls to memset() with
a destination pointer that points to a non-POD type. This can flag such horrible bugs as overwriting vptrs when a previously POD structure is suddenly given a virtual method, or creating objects that crash on practically any use by zero-ing out a member when its changed from a const char* to a std::string, etc. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130299 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaChecking.cpp34
-rw-r--r--test/SemaCXX/warn-non-pod-memset.cpp45
4 files changed, 86 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9a29ba2be0..8c863c2d1d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -261,6 +261,11 @@ def err_builtin_definition : Error<"definition of builtin function %0">;
def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
+def warn_non_pod_memset : Warning<
+ "destination for this memset call is a pointer to a non-POD type %0">,
+ InGroup<DiagGroup<"non-pod-memset">>;
+def note_non_pod_memset_silence : Note<
+ "explicitly cast the pointer to silence this warning">;
/// main()
// static/inline main() are not errors in C, just in C++.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index da6755fad0..691a17b63c 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5516,6 +5516,8 @@ private:
unsigned format_idx, unsigned firstDataArg,
bool isPrintf);
+ void CheckMemsetArguments(const CallExpr *Call);
+
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 9dec259696..6b219612d1 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -318,6 +318,10 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
TheCall->getCallee()->getLocStart());
}
+ // Memset handling
+ if (FnInfo->isStr("memset"))
+ CheckMemsetArguments(TheCall);
+
return false;
}
@@ -1791,6 +1795,36 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
}
}
+//===--- CHECK: Standard memory functions ---------------------------------===//
+
+/// \brief Check for dangerous or invalid arguments to memset().
+///
+/// This issues warnings on known problematic or dangerous or unspecified
+/// arguments to the standard 'memset' function call.
+///
+/// \param Call The call expression to diagnose.
+void Sema::CheckMemsetArguments(const CallExpr *Call) {
+ assert(Call->getNumArgs() == 3 && "Unexpected number of arguments to memset");
+ const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts();
+
+ QualType DestTy = Dest->getType();
+ if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
+ QualType PointeeTy = DestPtrTy->getPointeeType();
+ if (!PointeeTy->isPODType()) {
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_non_pod_memset)
+ << PointeeTy << Call->getCallee()->getSourceRange());
+
+ SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_non_pod_memset_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ }
+ }
+}
+
//===--- CHECK: Return Address of Stack Variable --------------------------===//
static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars);
diff --git a/test/SemaCXX/warn-non-pod-memset.cpp b/test/SemaCXX/warn-non-pod-memset.cpp
new file mode 100644
index 0000000000..03e626e708
--- /dev/null
+++ b/test/SemaCXX/warn-non-pod-memset.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+extern void *memset(void *, int, unsigned);
+
+// Several POD types that should not warn.
+struct S1 {} s1;
+struct S2 { int x; } s2;
+struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;
+
+// Non-POD types that should warn.
+struct X1 { X1(); } x1;
+struct X2 { ~X2(); } x2;
+struct X3 { virtual void f(); } x3;
+struct X4 : X2 {} x4;
+struct X5 : virtual S1 {} x5;
+
+void test_warn() {
+ memset(&x1, 0, sizeof x1); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x2, 0, sizeof x2); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x3, 0, sizeof x3); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x4, 0, sizeof x4); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x5, 0, sizeof x5); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+}
+
+void test_nowarn() {
+ memset(&s1, 0, sizeof s1);
+ memset(&s2, 0, sizeof s2);
+ memset(&s3, 0, sizeof s3);
+
+ // Unevaluated code shouldn't warn.
+ (void)sizeof memset(&x1, 0, sizeof x1);
+
+ // Dead code shouldn't warn.
+ if (false) memset(&x1, 0, sizeof x1);
+}