diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 58de9fe48162b..f978a40682faa 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -10356,15 +10356,24 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, bool NonTriviallyCopyableCXXRecord = getLangOpts().CPlusPlus && RD->isCompleteDefinition() && !PointeeTy.isTriviallyCopyableType(Context); + // We don't warn about bzero or zero memsetting as these are an idiomatic + // mechanism for ensuring objects do not have stale data. + bool IsNonZeroInitMemcall = false; + if (BId == Builtin::BImemset) { + const Expr *Initializer = Call->getArg(1)->IgnoreImpCasts(); + auto IntegerConstant = dyn_cast(Initializer); + IsNonZeroInitMemcall = + !IntegerConstant || IntegerConstant->getValue() != 0; + } - if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && + if (IsNonZeroInitMemcall && RD->isNonTrivialToPrimitiveDefaultInitialize()) { DiagRuntimeBehavior(Dest->getExprLoc(), Dest, PDiag(diag::warn_cstruct_memaccess) << ArgIdx << FnName << PointeeTy << 0); SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); - } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && - NonTriviallyCopyableCXXRecord && ArgIdx == 0) { + } else if (IsNonZeroInitMemcall && NonTriviallyCopyableCXXRecord && + ArgIdx == 0) { // FIXME: Limiting this warning to dest argument until we decide // whether it's valid for source argument too. DiagRuntimeBehavior(Dest->getExprLoc(), Dest, diff --git a/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c b/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c index 9cdb98e55458b..5ed4ca0bddde1 100644 --- a/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c +++ b/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c @@ -26,35 +26,50 @@ struct PtrAuthTrivial { struct PtrAuthNonTrivial0 { int f0; - int * AQ f1; // c-note 2 {{non-trivial to copy}} + int * AQ f1; // #PtrAuthNonTrivial0_f1 int f2; }; struct PtrAuthNonTrivial1 { - int * AQ f0; // c-note 2 {{non-trivial to copy}} + int * AQ f0; // #PtrAuthNonTrivial1_f0 int f1; struct PtrAuthNonTrivial0 f2; }; -void testPtrAuthTrivial(struct PtrAuthTrivial *d, struct PtrAuthTrivial *s) { +void testPtrAuthTrivial(struct PtrAuthTrivial *d, struct PtrAuthTrivial *s, int i) { memset(d, 0, sizeof(struct PtrAuthTrivial)); memset(d, 1, sizeof(struct PtrAuthTrivial)); + memset(d, i, sizeof(struct PtrAuthTrivial)); bzero(d, sizeof(struct PtrAuthTrivial)); memcpy(d, s, sizeof(struct PtrAuthTrivial)); memmove(d, s, sizeof(struct PtrAuthTrivial)); } void testPtrAuthNonTrivial1(struct PtrAuthNonTrivial1 *d, - struct PtrAuthNonTrivial1 *s) { - memset(d, 0, sizeof(struct PtrAuthNonTrivial1)); // cxx-warning {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} // cxx-note {{explicitly cast the pointer to silence}} - memset(d, 1, sizeof(struct PtrAuthNonTrivial1)); // cxx-warning {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} // cxx-note {{explicitly cast the pointer to silence}} - bzero(d, sizeof(struct PtrAuthNonTrivial1)); // cxx-warning {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} // cxx-note {{explicitly cast the pointer to silence}} - memcpy(d, s, sizeof(struct PtrAuthNonTrivial1)); - // c-warning@-1 {{that is not trivial to primitive-copy}} - // cxx-warning@-2 {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} - // expected-note@-3 {{explicitly cast the pointer to silence}} - memmove(d, s, sizeof(struct PtrAuthNonTrivial1)); - // c-warning@-1 {{that is not trivial to primitive-copy}} - // cxx-warning@-2 {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} - // expected-note@-3 {{explicitly cast the pointer to silence}} + struct PtrAuthNonTrivial1 *s, + int i) { + memset(d, 0, sizeof(struct PtrAuthNonTrivial1)); + memset(d, 1, sizeof(struct PtrAuthNonTrivial1)); // #memset_d_1 + // cxx-warning@#memset_d_1 {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} + // cxx-note@#memset_d_1 {{explicitly cast the pointer to silence}} + + memset(d, i, sizeof(struct PtrAuthNonTrivial1)); /// #memset_d_i + // cxx-warning@#memset_d_i {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} + // cxx-note@#memset_d_i {{explicitly cast the pointer to silence}} + + bzero(d, sizeof(struct PtrAuthNonTrivial1)); + + memcpy(d, s, sizeof(struct PtrAuthNonTrivial1)); // #memcpy_d + // c-warning@#memcpy_d {{that is not trivial to primitive-copy}} + // c-note@#PtrAuthNonTrivial0_f1 {{non-trivial to copy}} + // c-note@#PtrAuthNonTrivial1_f0 {{non-trivial to copy}} + // cxx-warning@#memcpy_d {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} + // expected-note@#memcpy_d {{explicitly cast the pointer to silence}} + + memmove(d, s, sizeof(struct PtrAuthNonTrivial1)); // #memmove_d + // c-warning@#memmove_d {{that is not trivial to primitive-copy}} + // c-note@#PtrAuthNonTrivial0_f1 {{non-trivial to copy}} + // c-note@#PtrAuthNonTrivial1_f0 {{non-trivial to copy}} + // cxx-warning@#memmove_d {{is a pointer to non-trivially copyable type 'struct PtrAuthNonTrivial1'}} + // expected-note@#memmove_d {{explicitly cast the pointer to silence}} } diff --git a/clang/test/SemaCXX/warn-memaccess.cpp b/clang/test/SemaCXX/warn-memaccess.cpp index 2e60539b3e48e..2a27d57d3eec6 100644 --- a/clang/test/SemaCXX/warn-memaccess.cpp +++ b/clang/test/SemaCXX/warn-memaccess.cpp @@ -9,8 +9,14 @@ class TriviallyCopyable {}; class NonTriviallyCopyable { NonTriviallyCopyable(const NonTriviallyCopyable&);}; struct Incomplete; +struct Polymorphic { + virtual ~Polymorphic(); +}; + + void test_bzero(TriviallyCopyable* tc, NonTriviallyCopyable *ntc, + Polymorphic *p, Incomplete* i) { // OK bzero(tc, sizeof(*tc)); @@ -18,29 +24,62 @@ void test_bzero(TriviallyCopyable* tc, // OK bzero(i, 10); - // expected-warning@+2{{first argument in call to 'bzero' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} - // expected-note@+1{{explicitly cast the pointer to silence this warning}} + // OK bzero(ntc, sizeof(*ntc)); // OK bzero((void*)ntc, sizeof(*ntc)); + + bzero(p, sizeof(*p)); // #bzerodynamic + // expected-warning@#bzerodynamic {{destination for this 'bzero' call is a pointer to dynamic class 'Polymorphic'; vtable pointer will be overwritten}} + // expected-note@#bzerodynamic {{explicitly cast the pointer to silence this warning}} } void test_memset(TriviallyCopyable* tc, NonTriviallyCopyable *ntc, - Incomplete* i) { + Polymorphic *p, + Incomplete* i, int NonconstantInit) { // OK memset(tc, 0, sizeof(*tc)); // OK memset(i, 0, 10); - // expected-warning@+2{{first argument in call to 'memset' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} - // expected-note@+1{{explicitly cast the pointer to silence this warning}} memset(ntc, 0, sizeof(*ntc)); // OK memset((void*)ntc, 0, sizeof(*ntc)); + + // OK + memset(p, 0, sizeof(*p)); // #memset0dynamic + // expected-warning@#memset0dynamic {{destination for this 'memset' call is a pointer to dynamic class 'Polymorphic'; vtable pointer will be overwritten}} + // expected-note@#memset0dynamic {{explicitly cast the pointer to silence this warning}} + + // OK + memset(tc, 1, sizeof(*tc)); + + // OK + memset(i, 1, 10); + + memset(ntc, 1, sizeof(*ntc)); // #memset1ntc + // expected-warning@#memset1ntc {{first argument in call to 'memset' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@#memset1ntc {{explicitly cast the pointer to silence this warning}} + + // OK + memset((void*)ntc, 1, sizeof(*ntc)); + + // OK + memset(tc, NonconstantInit, sizeof(*tc)); + + // OK + memset(i, NonconstantInit, 10); + + memset(ntc, NonconstantInit, sizeof(*ntc)); // #memsetnonconstntc + // expected-warning@#memsetnonconstntc {{first argument in call to 'memset' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@#memsetnonconstntc {{explicitly cast the pointer to silence this warning}} + + // OK + memset((void*)ntc, NonconstantInit, sizeof(*ntc)); } diff --git a/clang/test/SemaObjC/warn-nontrivial-struct-memaccess.m b/clang/test/SemaObjC/warn-nontrivial-struct-memaccess.m index a6eb485ceabe5..4ed12583afbaf 100644 --- a/clang/test/SemaObjC/warn-nontrivial-struct-memaccess.m +++ b/clang/test/SemaObjC/warn-nontrivial-struct-memaccess.m @@ -12,28 +12,51 @@ struct NonTrivial0 { int f0; - __weak id f1; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}} + __weak id f1;// #NonTrivial0_f1 volatile int f2; id f3[10]; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}} }; struct NonTrivial1 { - id f0; // expected-note 2 {{non-trivial to default-initialize}} expected-note 2 {{non-trivial to copy}} + id f0; // #NonTrivial1_f0 int f1; struct NonTrivial0 f2; }; -void testTrivial(struct Trivial *d, struct Trivial *s) { +void testNonTrivial0(struct NonTrivial1 *d, struct NonTrivial1 *s, int i) { + memset(d, 0, sizeof(struct NonTrivial1)); +} +void testTrivial(struct Trivial *d, struct Trivial *s, int i) { memset(d, 0, sizeof(struct Trivial)); + memset(d, 1, sizeof(struct Trivial)); + memset(d, i, sizeof(struct Trivial)); bzero(d, sizeof(struct Trivial)); memcpy(d, s, sizeof(struct Trivial)); memmove(d, s, sizeof(struct Trivial)); } -void testNonTrivial1(struct NonTrivial1 *d, struct NonTrivial1 *s) { - memset(d, 0, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-default-initialize}} expected-note {{explicitly cast the pointer to silence}} +void testNonTrivial1(struct NonTrivial1 *d, struct NonTrivial1 *s, int i) { + memset(d, 0, sizeof(struct NonTrivial1)); + memset(d, 1, sizeof(struct NonTrivial1)); // #memset_d_1 + // expected-warning@#memset_d_1 {{that is not trivial to primitive-default-initialize}} + // expected-note@#NonTrivial1_f0 {{non-trivial to default-initialize}} + // expected-note@#NonTrivial0_f1 {{non-trivial to default-initialize}} + // expected-note@#memset_d_1 {{explicitly cast the pointer to silence}} + memset(d, i, sizeof(struct NonTrivial1)); // #memset_d_i + // expected-warning@#memset_d_i {{that is not trivial to primitive-default-initialize}} + // expected-note@#NonTrivial1_f0 {{non-trivial to default-initialize}} + // expected-note@#NonTrivial0_f1 {{non-trivial to default-initialize}} + // expected-note@#memset_d_i {{explicitly cast the pointer to silence}} memset((void *)d, 0, sizeof(struct NonTrivial1)); - bzero(d, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-default-initialize}} expected-note {{explicitly cast the pointer to silence}} - memcpy(d, s, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}} - memmove(d, s, sizeof(struct NonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}} + bzero(d, sizeof(struct NonTrivial1)); + memcpy(d, s, sizeof(struct NonTrivial1)); // #memcpy_d + // expected-warning@#memcpy_d {{that is not trivial to primitive-copy}} + // expected-note@#NonTrivial1_f0 {{non-trivial to copy}} + // expected-note@#NonTrivial0_f1 {{non-trivial to copy}} + // expected-note@#memcpy_d {{explicitly cast the pointer to silence}} + memmove(d, s, sizeof(struct NonTrivial1)); // #memmove_d + // expected-warning@#memmove_d {{that is not trivial to primitive-copy}} + // expected-note@#NonTrivial1_f0 {{non-trivial to copy}} + // expected-note@#NonTrivial0_f1 {{non-trivial to copy}} + // expected-note@#memmove_d {{explicitly cast the pointer to silence}} }