From fc9fdbcc09f214c6e0ea4a2b5bf61aa28e6082ef Mon Sep 17 00:00:00 2001 From: Rion Bora <223810819+GoldenEmperor1177@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:18:38 +0530 Subject: [PATCH] MDEV-40545 mariadb-binlog --force-read loops on truncated events What was wrong: With --force-read, Log_event::read_log_event() returned a synthetic "Encrypted event" (Unknown_log_event) for every read error. A truncated event is such an error, so mariadb-binlog printed a fake event instead of stopping, and on most truncated binlogs it then never stopped at all. How it is fixed: The synthetic event is meant for encrypted events that mariadb-binlog cannot decrypt (MDEV-11319). It is now returned only for a decryption failure. Other read errors, like a truncated event or an out of memory error, are critical: continuing after them cannot produce meaningful output, so they are reported and mariadb-binlog stops as it does without --force-read. How it is tested: main.mysqlbinlog_force_read_truncated reads two truncated binlogs from std_data, one with a truncated event header and one with a truncated event body. The test loops forever without the fix. --- .../mysqlbinlog_force_read_truncated.result | 18 ++++++++++++++++++ .../mysqlbinlog_force_read_truncated.test | 13 +++++++++++++ .../std_data/truncated_binlog_body.000001 | Bin 0 -> 50 bytes .../std_data/truncated_binlog_header.000001 | Bin 0 -> 17 bytes sql/log_event.cc | 9 ++++----- 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 mysql-test/main/mysqlbinlog_force_read_truncated.result create mode 100644 mysql-test/main/mysqlbinlog_force_read_truncated.test create mode 100644 mysql-test/std_data/truncated_binlog_body.000001 create mode 100644 mysql-test/std_data/truncated_binlog_header.000001 diff --git a/mysql-test/main/mysqlbinlog_force_read_truncated.result b/mysql-test/main/mysqlbinlog_force_read_truncated.result new file mode 100644 index 00000000000..c61b2d1dc26 --- /dev/null +++ b/mysql-test/main/mysqlbinlog_force_read_truncated.result @@ -0,0 +1,18 @@ +# +# MDEV-40545: --force-read must not loop on a truncated event +# +# The event header is truncated +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; +/*!40019 SET @@session.max_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ERROR: Error in Log_event::read_log_event(): 'Event truncated' +ERROR: Could not read entry at offset 4: Error in log format or read error. +# The event body is truncated +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; +/*!40019 SET @@session.max_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ERROR: Error in Log_event::read_log_event(): 'Event truncated', data_len: 94, event_type: 15 +ERROR: Could not read entry at offset 4: Error in log format or read error. +# End of 11.4 tests diff --git a/mysql-test/main/mysqlbinlog_force_read_truncated.test b/mysql-test/main/mysqlbinlog_force_read_truncated.test new file mode 100644 index 00000000000..dde1747ac87 --- /dev/null +++ b/mysql-test/main/mysqlbinlog_force_read_truncated.test @@ -0,0 +1,13 @@ +--echo # +--echo # MDEV-40545: --force-read must not loop on a truncated event +--echo # + +--echo # The event header is truncated +--error 1 +--exec $MYSQL_BINLOG --short-form --force-read $MYSQL_TEST_DIR/std_data/truncated_binlog_header.000001 2>&1 + +--echo # The event body is truncated +--error 1 +--exec $MYSQL_BINLOG --short-form --force-read $MYSQL_TEST_DIR/std_data/truncated_binlog_body.000001 2>&1 + +--echo # End of 11.4 tests diff --git a/mysql-test/std_data/truncated_binlog_body.000001 b/mysql-test/std_data/truncated_binlog_body.000001 new file mode 100644 index 0000000000000000000000000000000000000000..ba231a91034f22ae231f3801d9ba0c706d5f172f GIT binary patch literal 50 xcmeyDl$rO(bhj5jBLf3N91te~F#`h&gQ=c@o`soiN@`MRx^7N>I#?J)0028x3KReU literal 0 HcmV?d00001 diff --git a/mysql-test/std_data/truncated_binlog_header.000001 b/mysql-test/std_data/truncated_binlog_header.000001 new file mode 100644 index 0000000000000000000000000000000000000000..c0917e96d8b32f2889f1355ddb358f5ef2b22603 GIT binary patch literal 17 WcmeyDl$poK#LU9X$N&Vq3=9Ax@&Z!; literal 0 HcmV?d00001 diff --git a/sql/log_event.cc b/sql/log_event.cc index 9e01ee66bc4..5cfd2818083 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -935,6 +935,10 @@ Log_event* Log_event::read_log_event(IO_CACHE* file, int *out_error, error= "Event too big"; goto err; case LOG_READ_DECRYPT: +#ifdef MYSQL_CLIENT + if (force_opt) + DBUG_RETURN(new Unknown_log_event()); +#endif error= "Event decryption failure"; goto err; case LOG_READ_CHECKSUM_FAILURE: @@ -956,11 +960,6 @@ err: if (unlikely(error)) { DBUG_ASSERT(!res); -#ifdef MYSQL_CLIENT - if (force_opt) - DBUG_RETURN(new Unknown_log_event()); -#endif - /* The SQL slave thread will check *out_error to know if there was an I/O error. Even if there is no "low-level" I/O errors