diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2011-04-27 07:05:31 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2011-04-27 07:05:31 +0000 |
commit | 7ccc95bceebb2d1c8fbe277c9e33bde7dc1ccbb1 (patch) | |
tree | a0ee5fcc77c93f3b704f7c4b821c800af8573118 | |
parent | d46a1125d43bcfd47fbd1206ebd1226863549390 (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.td | 5 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 34 | ||||
-rw-r--r-- | test/SemaCXX/warn-non-pod-memset.cpp | 45 |
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); +} |