From 941a465edd2d4ca20f966e1877ac67021091dba6 Mon Sep 17 00:00:00 2001 From: Fariha Shaikh Date: Thu, 26 Feb 2026 19:55:31 +0000 Subject: [PATCH] MDEV-38020 Master & relay log info files read 2^31 and above incorrectly Master and relay log positions are 64-bit unsigned but were read using atoi(), which only handles signed 32-bit integers. Values >= 2^31 overflow and corrupt after restart. Add init_ullongvar_from_file() using my_strtoll10() to correctly parse 64-bit values. Update rpl_rli.cc and rpl_mi.cc to use ulonglong variables and this new function. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. Reviewed-by: Brandon Nesterenko --- .../rpl/r/rpl_read_old_relay_log_info.result | 7 ++++++ .../rpl/t/rpl_read_old_relay_log_info.test | 25 +++++++++++++++++++ sql/rpl_mi.cc | 5 ++-- sql/rpl_rli.cc | 7 +++--- sql/slave.cc | 21 ++++++++++++++++ sql/slave.h | 2 ++ 6 files changed, 62 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result b/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result index 151a00a514b24..d4f7f3d982282 100644 --- a/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result +++ b/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result @@ -12,4 +12,11 @@ START SLAVE IO_THREAD; include/wait_for_slave_io_to_start.inc # Check that relay log coordinates are equal to those we saved in old-format_relay-log.info = , 0, slave-relay-bin.000001, 4 +# +# MDEV-38020: Master & relay log info files read 2^31 and above incorrectly +# +connection server_2; +include/stop_slave.inc +include/rpl_restart_server.inc [server_number=2 parameters: --skip-slave-start] +include/assert.inc [relay_log_pos should be 2147483648 after restart] include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test index d2206b5bef79a..db910d80c41a3 100644 --- a/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test +++ b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test @@ -44,5 +44,30 @@ if (`SELECT "$master_file" != "" OR --die log coordinates changed } +--echo # +--echo # MDEV-38020: Master & relay log info files read 2^31 and above incorrectly +--echo # + +--connection server_2 +--source include/stop_slave.inc + +# Create a relay-log.info file with a position value > 2^31 +--let $MYSQLD_DATADIR= `select @@datadir` +--remove_file $MYSQLD_DATADIR/relay-log.info +--write_file $MYSQLD_DATADIR/relay-log.info +./slave-relay-bin.000001 +2147483648 + +0 +EOF + +--let $rpl_server_number= 2 +--let $rpl_server_parameters= --skip-slave-start +--source include/rpl_restart_server.inc + +--let $assert_text= relay_log_pos should be 2147483648 after restart +--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = 2147483648 +--source include/assert.inc + --let $rpl_only_running_threads= 1 --source include/rpl_end.inc diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index b19a585f47ebf..bb77c46d57f57 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -448,7 +448,8 @@ file '%s')", fname); } mi->fd = fd; - int port, connect_retry, master_log_pos, lines; + int port, connect_retry, lines; + ulonglong master_log_pos; int ssl= 0, ssl_verify_server_cert= 0; float master_heartbeat_period= 0.0; char *first_non_digit; @@ -496,7 +497,7 @@ file '%s')", fname); else lines= 7; - if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || + if (init_ulonglongvar_from_file(&master_log_pos, &mi->file, 4) || init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) || init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") || init_strvar_from_file(mi->password, sizeof(mi->password), diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 320937ed82900..4ed2f55e8317c 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -321,7 +321,8 @@ Failed to open the existing relay log info file '%s' (errno %d)", } } - int relay_log_pos, master_log_pos, lines; + ulonglong relay_log_pos, master_log_pos; + int lines; char *first_non_digit; /* @@ -374,12 +375,12 @@ Failed to open the existing relay log info file '%s' (errno %d)", else DBUG_PRINT("info", ("relay_log_info file is in old format.")); - if (init_intvar_from_file(&relay_log_pos, + if (init_ulonglongvar_from_file(&relay_log_pos, &info_file, BIN_LOG_HEADER_SIZE) || init_strvar_from_file(group_master_log_name, sizeof(group_master_log_name), &info_file, "") || - init_intvar_from_file(&master_log_pos, &info_file, 0) || + init_ulonglongvar_from_file(&master_log_pos, &info_file, 0) || (lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY && init_intvar_from_file(&sql_delay, &info_file, 0))) { diff --git a/sql/slave.cc b/sql/slave.cc index 15eeae3145542..6e0b86fc968ac 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1608,6 +1608,27 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) DBUG_RETURN(1); } +int init_ulonglongvar_from_file(ulonglong* var, IO_CACHE* f, + ulonglong default_val) +{ + char buf[MY_INT64_NUM_DECIMAL_DIGITS]; + int error; + DBUG_ENTER("init_ulonglongvar_from_file"); + + + if (my_b_gets(f, buf, sizeof(buf))) + { + *var = (ulonglong) my_strtoll10(buf, (char**) 0, &error); + DBUG_RETURN(0); + } + else if (default_val) + { + *var = default_val; + DBUG_RETURN(0); + } + DBUG_RETURN(1); +} + int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val) { char buf[16]; diff --git a/sql/slave.h b/sql/slave.h index 02de9135c2a10..ce25bebf730ba 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -266,6 +266,8 @@ int apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd, struct rpl_group_info *rgi); int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); +int init_ulonglongvar_from_file(ulonglong* var, IO_CACHE* f, + ulonglong default_val); int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val);