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);
}
// 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;
}
///
/// \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.
// 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;
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) {
N::memset(&x1, 0, sizeof x1);
}
}
+
+