)]}'
{
  "commit": "5b8adb2a8a9232044c961d6cd98dd4731c6fd633",
  "tree": "fcf23beace2dbf93c70b988dbe869ae72fe6b250",
  "parents": [
    "dd543428c7a16860a74d28e9ece2c738bd645a14"
  ],
  "author": {
    "name": "Adil Burak Şen",
    "email": "56400880+adilburaksen@users.noreply.github.com",
    "time": "Fri Jun 05 07:16:59 2026 -0700"
  },
  "committer": {
    "name": "Copybara-Service",
    "email": "copybara-worker@google.com",
    "time": "Fri Jun 05 07:19:40 2026 -0700"
  },
  "message": "Fix RepeatedField::MergeFrom self-merge heap pointer disclosure (#27607)\n\n## Summary\n\n`RepeatedField\u003cT\u003e::MergeFrom` has an unsafe self-merge path. When `MergeFrom(self)` is called on a field at SOO capacity (2 elements for `int32_t`), `Reserve()` triggers a SOO→heap transition. The `other_is_soo` flag captured before `Reserve()` becomes stale — `other.elements(stale_true)` returns `soo_data_[]`, which now holds the raw `HeapRep*` pointer bytes. `UninitializedCopyN` then copies those bytes as `int32_t` values, appending two elements containing the low/high 32 bits of the heap address.\n\n`ABSL_DCHECK_NE(\u0026other, this)` caught this in debug builds but was compiled out with `-DNDEBUG`, so release builds proceeded silently and produced corrupted contents / heap-address disclosure.\n\n## Fix\n\nSelf-merge is undefined behavior. Rather than silently no-op, this turns it into a well-defined termination: an out-of-line `internal::LogSelfMergeAndAbort()` that fires `ABSL_LOG(FATAL)` in all build modes.\n\n```cpp\ntemplate \u003ctypename Element\u003e\ninline void RepeatedField\u003cElement\u003e::MergeFrom(const RepeatedField\u0026 other) {\n  if (ABSL_PREDICT_FALSE(\u0026other \u003d\u003d this)) {\n    PROTOBUF_NO_MERGE internal::LogSelfMergeAndAbort();\n  }\n  ...\n```\n\nThe abort helper is declared out-of-line (in `repeated_field.cc`) so the failure path does not pull `ABSL_LOG` streaming support into every inlined `MergeFrom` instantiation. The previously-existing `ABSL_DCHECK_NE(\u0026other, this)` is now dead code (the self-reference branch terminates before reaching it) and has been removed.\n\n## Test\n\n`RepeatedField.MergeFromSelfFailsWithATermination` exercises the SOO-capacity self-merge — the case that previously appended heap-pointer bytes in release builds — and asserts it now terminates:\n\n```cpp\nRepeatedField\u003cint32_t\u003e field;\nfield.Add(1);\nfield.Add(2);\nEXPECT_DEATH(field.MergeFrom(field), \"self-reference\");\n```\n\nCloses #27607\n\nCOPYBARA_INTEGRATE_REVIEW\u003dhttps://github.com/protocolbuffers/protobuf/pull/27607 from adilburaksen:fix/repeated-field-self-merge cbe6a42d7ae2ed8474fd4226f1aca0d349e7c452\nPiperOrigin-RevId: 927283856\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "c4b444b2ce69a95585980082dc1de3de244d428a",
      "old_mode": 33188,
      "old_path": "src/google/protobuf/repeated_field.cc",
      "new_id": "7172366700cab6a421c4b142626285e83e0ad48a",
      "new_mode": 33188,
      "new_path": "src/google/protobuf/repeated_field.cc"
    },
    {
      "type": "modify",
      "old_id": "8c805fab2713dc9e8574f1d46dec0e7de6f8470c",
      "old_mode": 33188,
      "old_path": "src/google/protobuf/repeated_field.h",
      "new_id": "2c1b8cd261519b2fe52184b65eae2452cf667acd",
      "new_mode": 33188,
      "new_path": "src/google/protobuf/repeated_field.h"
    },
    {
      "type": "modify",
      "old_id": "c36500e0657354936bd19b1ebc371527ad0e7298",
      "old_mode": 33188,
      "old_path": "src/google/protobuf/repeated_field_unittest.cc",
      "new_id": "c6b92272121c8b4659ed77e6c335aab689c74c03",
      "new_mode": 33188,
      "new_path": "src/google/protobuf/repeated_field_unittest.cc"
    }
  ]
}
