From 7ea645ace1636dee92a7eb2ba523f324684da13e Mon Sep 17 00:00:00 2001 From: pumisj Date: Tue, 25 Aug 2026 16:17:38 +0900 Subject: [PATCH 1/2] Initialize binlog event scalar members Initialize Log_event_header and Rows_event scalar fields in every constructor path. This prevents GCC 15 from diagnosing potentially uninitialized reads in Rows_log_event and also gives malformed-event early returns deterministic state. --- libs/mysql/binlog/event/binlog_event.cpp | 7 ++- libs/mysql/binlog/event/binlog_event.h | 7 ++- libs/mysql/binlog/event/rows_event.cpp | 4 ++ libs/mysql/binlog/event/rows_event.h | 4 ++ unittest/gunit/binlogevents/CMakeLists.txt | 1 + .../binlogevents/event_initialization-t.cc | 62 +++++++++++++++++++ 6 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 unittest/gunit/binlogevents/event_initialization-t.cc diff --git a/libs/mysql/binlog/event/binlog_event.cpp b/libs/mysql/binlog/event/binlog_event.cpp index 1f9edc9012a0..21f1b5dacf4b 100644 --- a/libs/mysql/binlog/event/binlog_event.cpp +++ b/libs/mysql/binlog/event/binlog_event.cpp @@ -232,7 +232,12 @@ bool Log_event_footer::event_checksum_test(unsigned char *event_buf, } Log_event_header::Log_event_header(Event_reader &reader) - : data_written(0), log_pos(0), m_is_valid(false) { + : type_code(ENUM_END_EVENT), + unmasked_server_id(0), + data_written(0), + log_pos(0), + flags(0), + m_is_valid(false) { BAPI_ENTER("Log_event_header::Log_event_header(Event_reader &)"); /* diff --git a/libs/mysql/binlog/event/binlog_event.h b/libs/mysql/binlog/event/binlog_event.h index 1036d5e781b6..1d11fd8001e7 100644 --- a/libs/mysql/binlog/event/binlog_event.h +++ b/libs/mysql/binlog/event/binlog_event.h @@ -724,7 +724,12 @@ class Log_event_header { typedef unsigned char Byte; explicit Log_event_header(Log_event_type type_code_arg = ENUM_END_EVENT) - : type_code(type_code_arg), data_written(0), log_pos(0), flags(0) { + : type_code(type_code_arg), + unmasked_server_id(0), + data_written(0), + log_pos(0), + flags(0), + m_is_valid(true) { when.tv_sec = 0; when.tv_usec = 0; } diff --git a/libs/mysql/binlog/event/rows_event.cpp b/libs/mysql/binlog/event/rows_event.cpp index cf326894dfd5..544db1c46a0a 100644 --- a/libs/mysql/binlog/event/rows_event.cpp +++ b/libs/mysql/binlog/event/rows_event.cpp @@ -407,8 +407,12 @@ Table_map_event::Optional_metadata_fields::Optional_metadata_fields( Rows_event::Rows_event(const char *buf, const Format_description_event *fde) : Binary_log_event(&buf, fde), + m_type(ENUM_END_EVENT), m_table_id(0), + m_flags(0), m_width(0), + n_bits_len(0), + var_header_len(0), columns_before_image(0), columns_after_image(0), row(0) { diff --git a/libs/mysql/binlog/event/rows_event.h b/libs/mysql/binlog/event/rows_event.h index 34ef92cc4495..a7750a66970f 100644 --- a/libs/mysql/binlog/event/rows_event.h +++ b/libs/mysql/binlog/event/rows_event.h @@ -919,8 +919,12 @@ class Rows_event : public Binary_log_event { */ explicit Rows_event(Log_event_type type_arg) : Binary_log_event(type_arg), + m_type(type_arg), m_table_id(0), + m_flags(0), m_width(0), + n_bits_len(0), + var_header_len(0), columns_before_image(0), columns_after_image(0), row(0) {} diff --git a/unittest/gunit/binlogevents/CMakeLists.txt b/unittest/gunit/binlogevents/CMakeLists.txt index 097ea5047a0d..2e0056e70cf2 100644 --- a/unittest/gunit/binlogevents/CMakeLists.txt +++ b/unittest/gunit/binlogevents/CMakeLists.txt @@ -32,6 +32,7 @@ INCLUDE_DIRECTORIES(SYSTEM ${GMOCK_INCLUDE_DIRS}) # Add tests SET(TESTS + event_initialization gno_intervals grow_calculator gtids diff --git a/unittest/gunit/binlogevents/event_initialization-t.cc b/unittest/gunit/binlogevents/event_initialization-t.cc new file mode 100644 index 000000000000..fc3d3b073508 --- /dev/null +++ b/unittest/gunit/binlogevents/event_initialization-t.cc @@ -0,0 +1,62 @@ +/* Copyright (c) 2026, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is designed to work with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have either included with the + program or referenced in the documentation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include + +#include + +#include "mysql/binlog/event/binlog_event.h" +#include "mysql/binlog/event/control_events.h" +#include "mysql/binlog/event/rows_event.h" + +namespace mysql::binlog::event::unittests { + +TEST(EventInitializationTest, LogEventHeaderDefaults) { + Log_event_header header; + + EXPECT_EQ(0, header.when.tv_sec); + EXPECT_EQ(0, header.when.tv_usec); + EXPECT_EQ(ENUM_END_EVENT, header.type_code); + EXPECT_EQ(0U, header.unmasked_server_id); + EXPECT_EQ(0U, header.data_written); + EXPECT_EQ(0U, header.log_pos); + EXPECT_EQ(0U, header.flags); + EXPECT_TRUE(header.get_is_valid()); +} + +TEST(EventInitializationTest, MalformedRowsEventHasDeterministicState) { + const Format_description_event fde(BINLOG_VERSION, "8.0.0"); + std::array buffer{}; + buffer[EVENT_TYPE_OFFSET] = static_cast(WRITE_ROWS_EVENT); + buffer[EVENT_LEN_OFFSET] = static_cast(buffer.size()); + + Rows_event event(buffer.data(), &fde); + + EXPECT_FALSE(event.header()->get_is_valid()); + EXPECT_EQ(0U, event.get_table_id()); + EXPECT_EQ(0U, event.get_flags()); + EXPECT_EQ(0U, event.get_width()); + EXPECT_EQ(0U, event.get_null_bits_len()); +} + +} // namespace mysql::binlog::event::unittests From 935ad9905cd6cd4bdeebb9175cd90f06a9a0054a Mon Sep 17 00:00:00 2001 From: pumisj Date: Tue, 29 Sep 2026 02:40:49 +0900 Subject: [PATCH 2/2] Use in-class initializers for binlog event defaults --- libs/mysql/binlog/event/binlog_event.cpp | 8 +------- libs/mysql/binlog/event/binlog_event.h | 17 ++++++----------- libs/mysql/binlog/event/rows_event.cpp | 4 ---- libs/mysql/binlog/event/rows_event.h | 13 +++++-------- 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/libs/mysql/binlog/event/binlog_event.cpp b/libs/mysql/binlog/event/binlog_event.cpp index 21f1b5dacf4b..35877d6b8930 100644 --- a/libs/mysql/binlog/event/binlog_event.cpp +++ b/libs/mysql/binlog/event/binlog_event.cpp @@ -231,13 +231,7 @@ bool Log_event_footer::event_checksum_test(unsigned char *event_buf, return res; } -Log_event_header::Log_event_header(Event_reader &reader) - : type_code(ENUM_END_EVENT), - unmasked_server_id(0), - data_written(0), - log_pos(0), - flags(0), - m_is_valid(false) { +Log_event_header::Log_event_header(Event_reader &reader) : m_is_valid(false) { BAPI_ENTER("Log_event_header::Log_event_header(Event_reader &)"); /* diff --git a/libs/mysql/binlog/event/binlog_event.h b/libs/mysql/binlog/event/binlog_event.h index 1d11fd8001e7..5022965b2aa2 100644 --- a/libs/mysql/binlog/event/binlog_event.h +++ b/libs/mysql/binlog/event/binlog_event.h @@ -691,22 +691,22 @@ class Log_event_header { Event type extracted from the header. In the server, it is decoded by read_log_event(), but adding here for complete decoding. */ - Log_event_type type_code; + Log_event_type type_code{ENUM_END_EVENT}; /* The server id read from the Binlog. */ - unsigned int unmasked_server_id; + unsigned int unmasked_server_id{0}; /* Length of an event, which will be written by write() function */ - size_t data_written; + size_t data_written{0}; /* The offset in the log where this event originally appeared (it is preserved in relay logs, making SHOW REPLICA STATUS able to print coordinates of the event in the master's binlog). */ - unsigned long long log_pos; + unsigned long long log_pos{0}; /* 16 or less flags depending on the version of the binary log. @@ -714,7 +714,7 @@ class Log_event_header { LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for notes. */ - uint16_t flags; + uint16_t flags{0}; /** The following type definition is to be used whenever data is placed @@ -724,12 +724,7 @@ class Log_event_header { typedef unsigned char Byte; explicit Log_event_header(Log_event_type type_code_arg = ENUM_END_EVENT) - : type_code(type_code_arg), - unmasked_server_id(0), - data_written(0), - log_pos(0), - flags(0), - m_is_valid(true) { + : type_code(type_code_arg), m_is_valid(true) { when.tv_sec = 0; when.tv_usec = 0; } diff --git a/libs/mysql/binlog/event/rows_event.cpp b/libs/mysql/binlog/event/rows_event.cpp index 544db1c46a0a..cf326894dfd5 100644 --- a/libs/mysql/binlog/event/rows_event.cpp +++ b/libs/mysql/binlog/event/rows_event.cpp @@ -407,12 +407,8 @@ Table_map_event::Optional_metadata_fields::Optional_metadata_fields( Rows_event::Rows_event(const char *buf, const Format_description_event *fde) : Binary_log_event(&buf, fde), - m_type(ENUM_END_EVENT), m_table_id(0), - m_flags(0), m_width(0), - n_bits_len(0), - var_header_len(0), columns_before_image(0), columns_after_image(0), row(0) { diff --git a/libs/mysql/binlog/event/rows_event.h b/libs/mysql/binlog/event/rows_event.h index a7750a66970f..11512df1697b 100644 --- a/libs/mysql/binlog/event/rows_event.h +++ b/libs/mysql/binlog/event/rows_event.h @@ -921,10 +921,7 @@ class Rows_event : public Binary_log_event { : Binary_log_event(type_arg), m_type(type_arg), m_table_id(0), - m_flags(0), m_width(0), - n_bits_len(0), - var_header_len(0), columns_before_image(0), columns_after_image(0), row(0) {} @@ -957,16 +954,16 @@ class Rows_event : public Binary_log_event { // Maximum number of columns. static constexpr const int max_fields{4096}; - Log_event_type m_type; /** Actual event type */ + Log_event_type m_type{ENUM_END_EVENT}; /** Actual event type */ /** Post header content */ Table_id m_table_id; - uint16_t m_flags; /** Flags for row-level events */ + uint16_t m_flags{0}; /** Flags for row-level events */ /* Body of the event */ - unsigned long m_width; /** The width of the columns bitmap */ - uint32_t n_bits_len; /** value determined by (m_width + 7) / 8 */ - uint16_t var_header_len; + unsigned long m_width; /** The width of the columns bitmap */ + uint32_t n_bits_len{0}; /** value determined by (m_width + 7) / 8 */ + uint16_t var_header_len{0}; std::vector columns_before_image; std::vector columns_after_image;