Teach the warning about non-POD memset/memcpy/memmove to deal with the
__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
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 6591069..577c88c 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5901,8 +5901,17 @@
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);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 81506bf..54900e0 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -320,12 +320,41 @@
}
// 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 @@
///
/// \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 @@
// 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;
diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp
index e7d095f..9a998f0 100644
--- a/test/SemaCXX/warn-bad-memaccess.cpp
+++ b/test/SemaCXX/warn-bad-memaccess.cpp
@@ -38,6 +38,46 @@
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 @@
N::memset(&x1, 0, sizeof x1);
}
}
+
+