https://github.com/serge-sans-paille updated 
https://github.com/llvm/llvm-project/pull/111434

>From 1904e7d4a3aeffd6f2f4ff397ae84fde37aa231a Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguel...@mozilla.com>
Date: Mon, 7 Oct 2024 15:30:24 +0200
Subject: [PATCH 1/4] [clang] Warn about memset/memcpy to NonTriviallyCopyable
 types

This implements a warning that's similar to what GCC does in that
context: both memcpy and memset require their first and second operand
to be trivially copyable, let's warn if that's not the case.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 ++++
 clang/lib/Sema/SemaChecking.cpp               | 24 +++++++++++++++++++
 clang/test/SemaCXX/constexpr-string.cpp       |  4 ++++
 3 files changed, 32 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 583475327c5227..d9bff4a559b3b7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -790,6 +790,10 @@ def warn_cstruct_memaccess : Warning<
   "%1 call is a pointer to record %2 that is not trivial to "
   "%select{primitive-default-initialize|primitive-copy}3">,
   InGroup<NonTrivialMemaccess>;
+def warn_cxxstruct_memaccess : Warning<
+  "%select{destination for|source of|first operand of|second operand of}0 this 
"
+  "%1 call is a pointer to record %2 that is not trivially-copyable">,
+  InGroup<NonTrivialMemaccess>;
 def note_nontrivial_field : Note<
   "field is non-trivial to %select{copy|default-initialize}0">;
 def err_non_trivial_c_union_in_invalid_context : Error<
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2bcb930acdcb57..46dda34d0ac8f3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8899,18 +8899,42 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
           << ArgIdx << FnName << PointeeTy
           << Call->getCallee()->getSourceRange());
     else if (const auto *RT = PointeeTy->getAs<RecordType>()) {
+
+      auto IsTriviallyCopyableCXXRecord = [](auto const *RT) {
+        auto const *D = RT->getDecl();
+        if (!D)
+          return true;
+        auto const *RD = dyn_cast<CXXRecordDecl>(D);
+        if (!RD)
+          return true;
+        RD = RD->getDefinition();
+        if (!RD)
+          return true;
+        return RD->isTriviallyCopyable();
+      };
+
       if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
           RT->getDecl()->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) &&
+                 !IsTriviallyCopyableCXXRecord(RT)) {
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cxxstruct_memaccess)
+                                << ArgIdx << FnName << PointeeTy);
       } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
                  RT->getDecl()->isNonTrivialToPrimitiveCopy()) {
         DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
                             PDiag(diag::warn_cstruct_memaccess)
                                 << ArgIdx << FnName << PointeeTy << 1);
         SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this);
+      } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
+                 !IsTriviallyCopyableCXXRecord(RT)) {
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cxxstruct_memaccess)
+                                << ArgIdx << FnName << PointeeTy);
       } else {
         continue;
       }
diff --git a/clang/test/SemaCXX/constexpr-string.cpp 
b/clang/test/SemaCXX/constexpr-string.cpp
index c456740ef7551f..26e2e138ef34e0 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -603,12 +603,16 @@ namespace MemcpyEtc {
   };
   constexpr bool test_nontrivial_memcpy() { // expected-error {{never produces 
a constant}}
     NonTrivial arr[3] = {};
+    // expected-warning@+2 {{source of this '__builtin_memcpy' call is a 
pointer to record 'NonTrivial' that is not trivially-copyable}}
+    // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
     __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 
2{{non-trivially-copyable}}
     return true;
   }
   static_assert(test_nontrivial_memcpy()); // expected-error {{constant}} 
expected-note {{in call}}
   constexpr bool test_nontrivial_memmove() { // expected-error {{never 
produces a constant}}
     NonTrivial arr[3] = {};
+    // expected-warning@+2 {{source of this '__builtin_memcpy' call is a 
pointer to record 'NonTrivial' that is not trivially-copyable}}
+    // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
     __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // expected-note 
2{{non-trivially-copyable}}
     return true;
   }

>From b2de17d1df5268dc4bfe772ba49fad166c907518 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguel...@mozilla.com>
Date: Tue, 8 Oct 2024 14:15:23 +0200
Subject: [PATCH 2/4] [compiler-rt] Silent warning related to memcpy of non
 trivially-copiable data

---
 compiler-rt/lib/memprof/memprof_rawprofile.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp 
b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
index a897648584828b..58e87fd833db7f 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
@@ -73,7 +73,7 @@ void SerializeSegmentsToBuffer(ArrayRef<LoadedModule> Modules,
         CHECK(Module.uuid_size() <= MEMPROF_BUILDID_MAX_SIZE);
         Entry.BuildIdSize = Module.uuid_size();
         memcpy(Entry.BuildId, Module.uuid(), Module.uuid_size());
-        memcpy(Ptr, &Entry, sizeof(SegmentEntry));
+        memcpy(Ptr, (void *)&Entry, sizeof(SegmentEntry));
         Ptr += sizeof(SegmentEntry);
         NumSegmentsRecorded++;
       }

>From ca9501c7e4bb0e4803d37bc7f595abe4a5c6b586 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguel...@mozilla.com>
Date: Tue, 8 Oct 2024 14:17:22 +0200
Subject: [PATCH 3/4] [libc++] Silent warning related to memcpy of non
 trivially-copyable data

---
 libcxx/include/__iterator/aliasing_iterator.h      | 2 +-
 libcxx/include/__memory/uninitialized_algorithms.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__iterator/aliasing_iterator.h 
b/libcxx/include/__iterator/aliasing_iterator.h
index 94ba577078b5e8..ed72d451980bca 100644
--- a/libcxx/include/__iterator/aliasing_iterator.h
+++ b/libcxx/include/__iterator/aliasing_iterator.h
@@ -102,7 +102,7 @@ struct __aliasing_iterator_wrapper {
 
     _LIBCPP_HIDE_FROM_ABI _Alias operator*() const _NOEXCEPT {
       _Alias __val;
-      __builtin_memcpy(&__val, std::__to_address(__base_), sizeof(value_type));
+      __builtin_memcpy(&__val, 
reinterpret_cast<void*>(std::__to_address(__base_)), sizeof(value_type));
       return __val;
     }
 
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h 
b/libcxx/include/__memory/uninitialized_algorithms.h
index dd72f3c10cf15a..e87cd5045c17f0 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -638,7 +638,7 @@ __uninitialized_allocator_relocate(_Alloc& __alloc, _Tp* 
__first, _Tp* __last, _
     __guard.__complete();
     std::__allocator_destroy(__alloc, __first, __last);
   } else {
-    __builtin_memcpy(__result, __first, sizeof(_Tp) * (__last - __first));
+    __builtin_memcpy((void*)__result, (void*)__first, sizeof(_Tp) * (__last - 
__first));
   }
 }
 

>From bc3b844b76a98c1dc1e725e2fd28dbdc965dd302 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguel...@mozilla.com>
Date: Tue, 8 Oct 2024 14:19:16 +0200
Subject: [PATCH 4/4] [ADT] Slient warning related to memcpy of non
 trivially-copyable data

---
 llvm/include/llvm/ADT/DenseMap.h    |  3 ++-
 llvm/include/llvm/ADT/Hashing.h     |  2 +-
 llvm/include/llvm/ADT/SmallVector.h | 11 ++++++-----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index f0f992f8eac389..5d5002dec16caf 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -442,7 +442,8 @@ class DenseMapBase : public DebugEpochBase {
     const size_t NumBuckets = getNumBuckets();
     if constexpr (std::is_trivially_copyable_v<KeyT> &&
                   std::is_trivially_copyable_v<ValueT>) {
-      memcpy(reinterpret_cast<void *>(Buckets), OtherBuckets,
+      memcpy(reinterpret_cast<void *>(Buckets),
+             reinterpret_cast<const void *>(OtherBuckets),
              NumBuckets * sizeof(BucketT));
     } else {
       const KeyT EmptyKey = getEmptyKey();
diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h
index 17dcf31c616aa7..c3e9f80bb204e9 100644
--- a/llvm/include/llvm/ADT/Hashing.h
+++ b/llvm/include/llvm/ADT/Hashing.h
@@ -508,7 +508,7 @@ struct hash_combine_recursive_helper {
       // with the variadic combine because that formation can have varying
       // argument types.
       size_t partial_store_size = buffer_end - buffer_ptr;
-      memcpy(buffer_ptr, &data, partial_store_size);
+      memcpy(buffer_ptr, reinterpret_cast<void *>(&data), partial_store_size);
 
       // If the store fails, our buffer is full and ready to hash. We have to
       // either initialize the hash state (on the first full buffer) or mix
diff --git a/llvm/include/llvm/ADT/SmallVector.h 
b/llvm/include/llvm/ADT/SmallVector.h
index bd3e887e36bce4..efeadeb60acfcd 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -509,15 +509,15 @@ class SmallVectorTemplateBase<T, true> : public 
SmallVectorTemplateCommon<T> {
   /// starting with "Dest", constructing elements into it as needed.
   template <typename T1, typename T2>
   static void uninitialized_copy(
-      T1 *I, T1 *E, T2 *Dest,
-      std::enable_if_t<std::is_same<std::remove_const_t<T1>, T2>::value> * =
-          nullptr) {
+      const T1 *I, const T1 *E, T2 *Dest,
+      std::enable_if_t<std::is_same<T1, T2>::value> * = nullptr) {
     // Use memcpy for PODs iterated by pointers (which includes SmallVector
     // iterators): std::uninitialized_copy optimizes to memmove, but we can
     // use memcpy here. Note that I and E are iterators and thus might be
     // invalid for memcpy if they are equal.
     if (I != E)
-      memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
+      memcpy(reinterpret_cast<void *>(Dest), reinterpret_cast<const void *>(I),
+             (E - I) * sizeof(T));
   }
 
   /// Double the size of the allocated memory, guaranteeing space for at
@@ -560,7 +560,8 @@ class SmallVectorTemplateBase<T, true> : public 
SmallVectorTemplateCommon<T> {
 public:
   void push_back(ValueParamT Elt) {
     const T *EltPtr = reserveForParamAndGetAddress(Elt);
-    memcpy(reinterpret_cast<void *>(this->end()), EltPtr, sizeof(T));
+    memcpy(reinterpret_cast<void *>(this->end()),
+           reinterpret_cast<const void *>(EltPtr), sizeof(T));
     this->set_size(this->size() + 1);
   }
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to