diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index d99aae6f52..7dac43d7fc 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -1035,7 +1035,7 @@ TEST(Movable, Works) { EXPECT_FALSE(internal::IsMovable::value); } -TEST(RepeatedField, MoveAdd) { +TEST(RepeatedPtrField, MoveAdd) { RepeatedPtrField field; TestAllTypes test_all_types; auto* optional_nested_message = @@ -1911,9 +1911,12 @@ TEST(RepeatedPtrField, SmallOptimization) { // Verify the string is where we think it is. EXPECT_EQ(&*array->begin(), &str); EXPECT_EQ(array->pointer_begin()[0], &str); + auto is_inlined = [array]() { + return std::less_equal{}(array, &*array->pointer_begin()) && + std::less{}(&*array->pointer_begin(), array + 1); + }; // The T** in pointer_begin points into the sso in the object. - EXPECT_TRUE(std::less_equal{}(array, &*array->pointer_begin())); - EXPECT_TRUE(std::less_equal{}(&*array->pointer_begin(), array + 1)); + EXPECT_TRUE(is_inlined()); // Adding a second object stops sso. std::string str2; @@ -1925,8 +1928,7 @@ TEST(RepeatedPtrField, SmallOptimization) { // We used some arena space now. EXPECT_LT(usage_before, arena.SpaceUsed()); // And the pointer_begin is not in the sso anymore. - EXPECT_FALSE(std::less_equal{}(array, &*array->pointer_begin()) && - std::less_equal{}(&*array->pointer_begin(), array + 1)); + EXPECT_FALSE(is_inlined()); } TEST(RepeatedPtrField, CopyAssign) { diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc index 6fe9f9af72..c716be5abd 100644 --- a/src/google/protobuf/repeated_ptr_field.cc +++ b/src/google/protobuf/repeated_ptr_field.cc @@ -9,6 +9,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include "google/protobuf/repeated_ptr_field.h" + #include #include #include @@ -59,11 +61,8 @@ void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { new_rep->elements[0] = tagged_rep_or_elem_; } else { Rep* old_rep = rep(); - if (old_rep->allocated_size > 0) { - memcpy(new_rep->elements, old_rep->elements, - old_rep->allocated_size * ptr_size); - } - new_rep->allocated_size = old_rep->allocated_size; + memcpy(new_rep, old_rep, + old_rep->allocated_size * ptr_size + kRepHeaderSize); size_t old_size = capacity * ptr_size + kRepHeaderSize; if (arena == nullptr) { diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index 3722fe0750..1f41a83f17 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -488,20 +488,20 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { // Pass value_arena and my_arena to avoid duplicate virtual call (value) // or load (mine). Value* value, Arena* value_arena, Arena* my_arena) { + using H = CommonHandler; // Ensure that either the value is in the same arena, or if not, we do the // appropriate thing: Own() it (if it's on heap and we're in an arena) or // copy it to our arena/heap (otherwise). if (my_arena != nullptr && value_arena == nullptr) { my_arena->Own(value); } else if (my_arena != value_arena) { + ABSL_DCHECK(value_arena != nullptr); auto* new_value = TypeHandler::NewFromPrototype(value, my_arena); - using H = CommonHandler; H::Merge(*value, new_value); - H::Delete(value, value_arena); value = new_value; } - UnsafeArenaAddAllocated(value); + UnsafeArenaAddAllocated(value); } template