Bug #120327 Unsigned integer wraparound in Binlog_sender::run() when binlog_row_event_max_size is set to a large value
Submitted: 23 Apr 7:46
Reporter: karry zhang (OCA) Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:MySQL 8.4 OS:Any
Assigned to: CPU Architecture:Any

[23 Apr 7:46] karry zhang
Description:
When binlog_row_event_max_size is set to a large value (e.g., its maximum ULONG_MAX), an unsigned integer wraparound occurs in Binlog_sender::run() (sql/rpl_binlog_sender.cc), causing the dump thread to reject legitimate
binlog events with the error: "log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source"

  Root Cause:

  In Binlog_sender::run():

  unsigned int max_event_size =
      std::max(m_thd->variables.max_allowed_packet,
               binlog_row_event_max_size + MAX_LOG_EVENT_HEADER);

  When binlog_row_event_max_size is near ULONG_MAX (after BLOCK_SIZE(256) alignment, it becomes 0xFFFFFFFFFFFFFF00),
   adding MAX_LOG_EVENT_HEADER (~300 bytes) causes an unsigned wraparound:

  0xFFFFFFFFFFFFFF00 + 300 = 0x10000000000000024 mod 2^64 = 44

  Then std::max(1GB, 44) returns 1GB, so max_event_size becomes 1073741824 (1GB) instead of the expected large
  value.

  This 1GB limit is then passed to Binlog_event_data_istream as m_max_event_size and checked in check_event_header()
   (sql/binlog_reader.cc):

  if (m_event_length > m_max_event_size)
      return m_error->set_type(Binlog_read_error::EVENT_TOO_LARGE);

  Any binlog event larger than 1GB (but within the valid 4-byte event_length range) is incorrectly rejected.

How to repeat:
  1. On the source, set binlog_row_event_max_size to its maximum value:
  mysqld --binlog-row-event-max-size=18446744073709551615
  2. Use row-based replication (binlog_format=ROW).
  3. Execute a transaction that produces a single row event larger than 1GB (e.g., a bulk INSERT with many rows that
   are not split because binlog_row_event_max_size is effectively unlimited).
  4. Connect a replica. The dump thread reads the binlog and fails at check_event_header() with:
  Got fatal error 1236 from source when reading data from binary log:
  'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source'

Suggested fix:
  The upper bound of binlog_row_event_max_size should be limited to binary_log::max_log_event_size (1GB), consistent
   with replica_max_allowed_packet. Because even if the source allows writing arbitrarily large row events, the
  replica cannot receive events exceeding replica_max_allowed_packet (max 1GB). Allowing binlog_row_event_max_size
  to exceed this limit is meaningless and leads to the wraparound bug.
[23 Apr 12:40] karry zhang
Hello, Verification Team, this is my patch.

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: diff.txt (text/plain), 617 bytes.