Fix aliasing Set calls.

Aliasing input make the memcpy calls overlap source and destination.

PiperOrigin-RevId: 738101367
diff --git a/src/google/protobuf/micro_string.cc b/src/google/protobuf/micro_string.cc
index ef0b0f2..acc4f97 100644
--- a/src/google/protobuf/micro_string.cc
+++ b/src/google/protobuf/micro_string.cc
@@ -65,7 +65,7 @@
     auto* h = micro_rep();
     if (h->capacity >= data.size()) {
       h->size = data.size();
-      memcpy(h->data(), data.data(), data.size());
+      memmove(h->data(), data.data(), data.size());
       return;
     }
     if (arena == nullptr) {
@@ -77,7 +77,7 @@
         auto* h = large_rep();
         if (h->capacity >= data.size()) {
           h->size = data.size();
-          memcpy(h->payload, data.data(), data.size());
+          memmove(h->payload, data.data(), data.size());
           return;
         }
         break;
@@ -105,7 +105,7 @@
   // If we fit in the inline space, use it.
   if (kHasInlineRep && data.size() <= inline_capacity) {
     set_inline_size(data.size());
-    memcpy(inline_head(), data.data(), data.size());
+    memmove(inline_head(), data.data(), data.size());
     return;
   }
 
diff --git a/src/google/protobuf/micro_string.h b/src/google/protobuf/micro_string.h
index deca870..9c1c723 100644
--- a/src/google/protobuf/micro_string.h
+++ b/src/google/protobuf/micro_string.h
@@ -263,7 +263,12 @@
   }
   void set_inline_size(size_t size) {
     ABSL_DCHECK(kHasInlineRep);
-    rep_ = reinterpret_cast<void*>(size << kTagShift);
+    size <<= kTagShift;
+    PROTOBUF_ASSUME(size <= 0xFF);
+    // Only overwrite the size byte to avoid clobbering the char bytes in case
+    // of aliasing.
+    rep_ = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(rep_) & ~0xFF) |
+                                   size);
     ABSL_DCHECK(is_inline());
   }
   char* inline_head() {
diff --git a/src/google/protobuf/micro_string_test.cc b/src/google/protobuf/micro_string_test.cc
index 8c52f92..e40f34b 100644
--- a/src/google/protobuf/micro_string_test.cc
+++ b/src/google/protobuf/micro_string_test.cc
@@ -412,6 +412,60 @@
             str_.SpaceUsedExcludingSelfLong());
 }
 
+TEST_P(MicroStringPrevTest, SelfSetView) {
+  const std::string control(str_.Get());
+
+  const size_t used = arena_space_used();
+  const bool will_reuse = str_.Capacity() != 0;
+  const size_t self_used = str_.SpaceUsedExcludingSelfLong();
+
+  str_.Set(str_.Get(), arena());
+  EXPECT_EQ(str_.Get(), control);
+
+  if (will_reuse) {
+    ExpectMemoryUsed(used, false, self_used);
+  }
+}
+
+TEST_P(MicroStringPrevTest, SelfSetSubstrView) {
+  const std::string control(str_.Get());
+  if (control.empty()) {
+    GTEST_SKIP() << "Can't substr an empty input.";
+  }
+
+  const size_t used = arena_space_used();
+  const bool will_reuse = str_.Capacity() != 0;
+  const size_t self_used = str_.SpaceUsedExcludingSelfLong();
+
+  str_.Set(str_.Get().substr(1), arena());
+  EXPECT_EQ(str_.Get(), absl::string_view(control).substr(1));
+
+  if (will_reuse) {
+    ExpectMemoryUsed(used, false, self_used);
+  }
+}
+
+TEST_P(MicroStringPrevTest, SelfSetSubstrViewConstantSize) {
+  const std::string control(str_.Get());
+  if (control.size() < 3) {
+    GTEST_SKIP() << "Can't substr an empty input.";
+  }
+
+  const size_t used = arena_space_used();
+  const bool will_reuse = str_.Capacity() != 0;
+  const size_t self_used = str_.SpaceUsedExcludingSelfLong();
+
+  // Here we test the fastpath in SetMaybeConstant.
+  // The input is an aliasing substr that overlaps with the destination, but
+  // with constant size to trigger the fastpath.
+  str_.Set(str_.Get().substr(1, 2), arena());
+  EXPECT_EQ(str_.Get(), absl::string_view(control).substr(1, 2));
+
+  if (will_reuse) {
+    ExpectMemoryUsed(used, false, self_used);
+  }
+}
+
 TEST_P(MicroStringPrevTest, CopyConstruct) {
   const size_t used = arena_space_used();
   MicroString copy(arena(), str_);