llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Oliver Hunt (ojhunt)

<details>
<summary>Changes</summary>

These warnings are triggered for zeroing initializers of non-trivially 
initializable and non-trivially copyable types.

This results in significant numbers of warnings in idiomatic object 
initialization code, where memset and similar are used to ensure no stale data 
is present in fields or padding bytes.

Addresses #<!-- -->156996

---
Full diff: https://github.com/llvm/llvm-project/pull/170577.diff


4 Files Affected:

- (modified) clang/lib/Sema/SemaChecking.cpp (+10-4) 
- (modified) clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c 
(+30-15) 
- (modified) clang/test/SemaCXX/warn-memaccess.cpp (+44-5) 
- (modified) clang/test/SemaObjC/warn-nontrivial-struct-memaccess.m (+31-8) 


``````````diff
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 58de9fe48162b..51c9010fcc244 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -10356,15 +10356,21 @@ 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<IntegerLiteral>(Initializer);
+        IsNonZeroInitMemcall = !IntegerConstant || IntegerConstant->getValue() 
!= 0;
+      }
 
-      if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
-          RD->isNonTrivialToPrimitiveDefaultInitialize()) {
+      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}}
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/170577
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to