From f7c5182b7cb413455a0fbbfbb8b773e12139c0a6 Mon Sep 17 00:00:00 2001
From: Dave Gosselin <dave.gosselin@mariadb.com>
Date: Wed, 18 Sep 2024 16:38:11 -0400
Subject: [PATCH] MDEV-31636 Memory leak in
 Sys_var_gtid_binlog_state::do_check()

Move memory allocations performed during Sys_var_gtid_binlog_state::do_check
to Sys_var_gtid_binlog_state::global_update where they will be freed before
the latter method returns.
---
 mysql-test/main/mdev-31636.result |  8 +++++
 mysql-test/main/mdev-31636.test   |  7 ++++
 sql/sys_vars.cc                   | 58 +++++++++++++++----------------
 3 files changed, 43 insertions(+), 30 deletions(-)
 create mode 100644 mysql-test/main/mdev-31636.result
 create mode 100644 mysql-test/main/mdev-31636.test

diff --git a/mysql-test/main/mdev-31636.result b/mysql-test/main/mdev-31636.result
new file mode 100644
index 00000000000..82dcd03027c
--- /dev/null
+++ b/mysql-test/main/mdev-31636.result
@@ -0,0 +1,8 @@
+RESET MASTER;
+SET
+@@global.gtid_binlog_state='1-1-101,2-1-2002',
+@@global.slave_parallel_mode=x;
+ERROR 42000: Variable 'slave_parallel_mode' can't be set to the value of 'x'
+SELECT @@global.gtid_binlog_state;
+@@global.gtid_binlog_state
+
diff --git a/mysql-test/main/mdev-31636.test b/mysql-test/main/mdev-31636.test
new file mode 100644
index 00000000000..b5affaef60c
--- /dev/null
+++ b/mysql-test/main/mdev-31636.test
@@ -0,0 +1,7 @@
+--source include/have_log_bin.inc
+RESET MASTER;
+--error ER_WRONG_VALUE_FOR_VAR
+SET
+  @@global.gtid_binlog_state='1-1-101,2-1-2002',
+  @@global.slave_parallel_mode=x;
+SELECT @@global.gtid_binlog_state;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 0af4b5e27fc..44302b3a507 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2016,15 +2016,6 @@ struct gtid_binlog_state_data { rpl_gtid *list; uint32 list_len; };
 bool
 Sys_var_gtid_binlog_state::do_check(THD *thd, set_var *var)
 {
-  String str, *res;
-  struct gtid_binlog_state_data *data;
-  rpl_gtid *list;
-  uint32 list_len;
-
-  DBUG_ASSERT(var->type == OPT_GLOBAL);
-
-  if (!(res= var->value->val_str(&str)))
-    return true;
   if (thd->in_active_multi_stmt_transaction())
   {
     my_error(ER_CANT_DO_THIS_DURING_AN_TRANSACTION, MYF(0));
@@ -2040,6 +2031,31 @@ Sys_var_gtid_binlog_state::do_check(THD *thd, set_var *var)
     my_error(ER_BINLOG_MUST_BE_EMPTY, MYF(0));
     return true;
   }
+  return false;
+}
+
+
+bool
+Sys_var_gtid_binlog_state::global_update(THD *thd, set_var *var)
+{
+  DBUG_ASSERT(var->type == OPT_GLOBAL);
+
+  if (!var->value)
+  {
+    my_error(ER_NO_DEFAULT, MYF(0), var->var->name.str);
+    return true;
+  }
+
+  bool result;
+  String str, *res;
+  struct gtid_binlog_state_data *data;
+  rpl_gtid *list;
+  uint32 list_len;
+
+  DBUG_ASSERT(var->type == OPT_GLOBAL);
+
+  if (!(res= var->value->val_str(&str)))
+    return true;
   if (res->length() == 0)
   {
     list= NULL;
@@ -2061,31 +2077,13 @@ Sys_var_gtid_binlog_state::do_check(THD *thd, set_var *var)
   data->list= list;
   data->list_len= list_len;
   var->save_result.ptr= data;
-  return false;
-}
-
-
-bool
-Sys_var_gtid_binlog_state::global_update(THD *thd, set_var *var)
-{
-  bool res;
-
-  DBUG_ASSERT(var->type == OPT_GLOBAL);
-
-  if (!var->value)
-  {
-    my_error(ER_NO_DEFAULT, MYF(0), var->var->name.str);
-    return true;
-  }
-
-  struct gtid_binlog_state_data *data=
-    (struct gtid_binlog_state_data *)var->save_result.ptr;
+  
   mysql_mutex_unlock(&LOCK_global_system_variables);
-  res= (reset_master(thd, data->list, data->list_len, 0) != 0);
+  result= (reset_master(thd, data->list, data->list_len, 0) != 0);
   mysql_mutex_lock(&LOCK_global_system_variables);
   my_free(data->list);
   my_free(data);
-  return res;
+  return result;
 }
 
 
-- 
2.30.9