Skip to content

Fix signed integer overflow in RepeatedField MergeFrom variants#28190

Open
momo-123-coder wants to merge 1 commit into
protocolbuffers:mainfrom
momo-123-coder:fix/merge-from-internal-integer-overflow
Open

Fix signed integer overflow in RepeatedField MergeFrom variants#28190
momo-123-coder wants to merge 1 commit into
protocolbuffers:mainfrom
momo-123-coder:fix/merge-from-internal-integer-overflow

Conversation

@momo-123-coder

@momo-123-coder momo-123-coder commented Jun 25, 2026

Copy link
Copy Markdown

Summary

  • MergeFromInternal<T> (repeated_ptr_field.cc:176) and MergeFrom<MessageLite> (repeated_ptr_field.cc:269) computed the post-merge element count using raw signed int addition with no overflow protection.
  • RepeatedField<Element>::MergeFrom (repeated_field.h:1261) passed a raw old_size + other_size expression directly to Reserve().
  • When current_size_ + from.current_size_ > INT_MAX, the addition wraps to a negative value (signed integer overflow — undefined behavior in C++). A negative new_size always satisfies the n <= Capacity() check in InternalReserve(), causing it to return a pointer past the end of the allocated buffer without growing it. The subsequent copy loop then writes from.current_size_ elements out of bounds — a heap-buffer-overflow.

MergeFromConcreteMessage() at line 238 of the same file already uses internal::CheckedAdd() correctly. This PR applies the same pattern to the three missing sites.

Changes

File Line Before After
repeated_ptr_field.cc 176 current_size_ + from.current_size_ internal::CheckedAdd(current_size_, from.current_size_)
repeated_ptr_field.cc 269 current_size_ + from.current_size_ internal::CheckedAdd(current_size_, from.current_size_)
repeated_field.h 1261 Reserve(old_size + other_size) Reserve(internal::CheckedAdd(old_size, other_size))

Crash reproduction (AddressSanitizer + UBSan)

runtime error: signed integer overflow: 4 + 2147483644 cannot be represented in type int

ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504000000038
WRITE of size 8 at 0x504000000038 thread T0
    #0 in MergeFromInternal  poc_merge_crash.cpp:136
    #1 in main               poc_merge_crash.cpp:189
0x504000000038 is located 0 bytes after 40-byte region

Test plan

  • Existing repeated-field unit tests pass
  • New test: merge two RepeatedField<int32> whose combined size exceeds INT_MAX — verify CheckedAdd aborts cleanly instead of writing out of bounds

@google-cla

google-cla Bot commented Jun 25, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@momo-123-coder momo-123-coder force-pushed the fix/merge-from-internal-integer-overflow branch from 468e63e to 059da13 Compare June 25, 2026 04:37
@momo-123-coder

Copy link
Copy Markdown
Author

/gclabot recheck

1 similar comment
@momo-123-coder

Copy link
Copy Markdown
Author

/gclabot recheck

MergeFromInternal<T> (line 176) and MergeFrom<MessageLite> (line 269)
in repeated_ptr_field.cc computed the post-merge size with raw signed
integer addition, which is undefined behavior when current_size_ +
from.current_size_ exceeds INT_MAX.  A negative new_size bypasses the
capacity check in InternalReserve(), causing it to return a pointer
past the end of the allocated buffer without growing it.  The
subsequent copy loop then writes from.current_size_ elements out of
bounds, resulting in a heap-buffer-overflow.

RepeatedField<Element>::MergeFrom in repeated_field.h had the same
pattern in its Reserve() call.

Apply internal::CheckedAdd() consistently to all three sites, matching
the pattern already used in MergeFromConcreteMessage() (line 238).
@momo-123-coder momo-123-coder force-pushed the fix/merge-from-internal-integer-overflow branch from 059da13 to be0c4fa Compare June 25, 2026 04:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant