]> granicus.if.org Git - clang/commitdiff
Teach the warning about non-POD memset/memcpy/memmove to deal with the
authorDouglas Gregor <dgregor@apple.com>
Thu, 16 Jun 2011 17:56:04 +0000 (17:56 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 16 Jun 2011 17:56:04 +0000 (17:56 +0000)
__builtin_ versions of these functions as well as the normal function
versions, so that it works on platforms where memset/memcpy/memmove
are macros that map down to the builtins (e.g., Darwin). Fixes
<rdar://problem/9372688>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133173 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaChecking.cpp
test/SemaCXX/warn-bad-memaccess.cpp

index 659106947ac3e9ec239009ef0ad82309536b3543..577c88c92709acc9722c458aefffe8775e16a38b 100644 (file)
@@ -5901,8 +5901,17 @@ private:
                                  unsigned format_idx, unsigned firstDataArg,
                                  bool isPrintf);
 
-  void CheckMemsetcpymoveArguments(const CallExpr *Call,
-                                   const IdentifierInfo *FnName);
+  /// \brief Enumeration used to describe which of the memory setting or copying
+  /// functions is being checked by \c CheckMemsetcpymoveArguments().
+  enum CheckedMemoryFunction {
+    CMF_Memset,
+    CMF_Memcpy,
+    CMF_Memmove
+  };
+  
+  void CheckMemsetcpymoveArguments(const CallExpr *Call, 
+                                   CheckedMemoryFunction CMF,
+                                   IdentifierInfo *FnName);
 
   void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
                             SourceLocation ReturnLoc);
index 81506bf571ab7e51fb6711c22d0b827914c85d87..54900e0cf15c095a1979b725317be498765ac2e9 100644 (file)
@@ -320,12 +320,41 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
   }
 
   // Memset/memcpy/memmove handling
-  if (FDecl->getLinkage() == ExternalLinkage &&
-      (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
-    if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") || 
-        FnInfo->isStr("memmove"))
-      CheckMemsetcpymoveArguments(TheCall, FnInfo);
+  int CMF = -1;
+  switch (FDecl->getBuiltinID()) {
+  case Builtin::BI__builtin_memset:
+  case Builtin::BI__builtin___memset_chk:
+  case Builtin::BImemset:
+    CMF = CMF_Memset;
+    break;
+    
+  case Builtin::BI__builtin_memcpy:
+  case Builtin::BI__builtin___memcpy_chk:
+  case Builtin::BImemcpy:
+    CMF = CMF_Memcpy;
+    break;
+    
+  case Builtin::BI__builtin_memmove:
+  case Builtin::BI__builtin___memmove_chk:
+  case Builtin::BImemmove:
+    CMF = CMF_Memmove;
+    break;
+    
+  default:
+    if (FDecl->getLinkage() == ExternalLinkage &&
+        (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
+      if (FnInfo->isStr("memset"))
+        CMF = CMF_Memset;
+      else if (FnInfo->isStr("memcpy"))
+        CMF = CMF_Memcpy;
+      else if (FnInfo->isStr("memmove"))
+        CMF = CMF_Memmove;
+    }
+    break;
   }
+   
+  if (CMF != -1)
+    CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
 
   return false;
 }
@@ -1856,14 +1885,14 @@ static QualType getSizeOfArgType(const Expr* E) {
 ///
 /// \param Call The call expression to diagnose.
 void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
-                                       const IdentifierInfo *FnName) {
+                                       CheckedMemoryFunction CMF,
+                                       IdentifierInfo *FnName) {
   // It is possible to have a non-standard definition of memset.  Validate
-  // we have the proper number of arguments, and if not, abort further
-  // checking.
-  if (Call->getNumArgs() != 3)
+  // we have enough arguments, and if not, abort further checking.
+  if (Call->getNumArgs() < 3)
     return;
 
-  unsigned LastArg = FnName->isStr("memset")? 1 : 2;
+  unsigned LastArg = (CMF == CMF_Memset? 1 : 2);
   const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts();
 
   // We have special checking when the length is a sizeof expression.
@@ -1934,8 +1963,7 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
       // Always complain about dynamic classes.
       if (isDynamicClassType(PointeeTy))
         DiagID = diag::warn_dyn_class_memaccess;
-      else if (PointeeTy.hasNonTrivialObjCLifetime() && 
-               !FnName->isStr("memset"))
+      else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
         DiagID = diag::warn_arc_object_memaccess;
       else
         continue;
index e7d095f0edcefb2375a03791dd2f9cef8c23ca6e..9a998f020cb4a5538a6356ddd4ae211512127eb8 100644 (file)
@@ -38,6 +38,46 @@ void test_warn() {
   memcpy(0, &x1, sizeof x1); // \
       // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class}} \
       // expected-note {{explicitly cast the pointer to silence this warning}}
+
+  __builtin_memset(&x1, 0, sizeof x1); // \
+      // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin_memset(&x2, 0, sizeof x2); // \
+      // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+
+  __builtin_memmove(&x1, 0, sizeof x1); // \
+      // expected-warning{{destination for this '__builtin_memmove' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin_memmove(0, &x1, sizeof x1); // \
+      // expected-warning{{source of this '__builtin_memmove' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin_memcpy(&x1, 0, sizeof x1); // \
+      // expected-warning{{destination for this '__builtin_memcpy' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin_memcpy(0, &x1, sizeof x1); // \
+      // expected-warning{{source of this '__builtin_memcpy' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+
+  __builtin___memset_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
+      // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin___memset_chk(&x2, 0, sizeof x2, sizeof x2); //                    \
+      // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+
+  __builtin___memmove_chk(&x1, 0, sizeof x1, sizeof x1); //                   \
+      // expected-warning{{destination for this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin___memmove_chk(0, &x1, sizeof x1, sizeof x1); //                   \
+      // expected-warning{{source of this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin___memcpy_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
+      // expected-warning{{destination for this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
+  __builtin___memcpy_chk(0, &x1, sizeof x1, sizeof x1); //                    \
+      // expected-warning{{source of this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
+      // expected-note {{explicitly cast the pointer to silence this warning}}
 }
 
 void test_nowarn(void *void_ptr) {
@@ -68,3 +108,5 @@ namespace N {
     N::memset(&x1, 0, sizeof x1);
   }
 }
+
+