From 0648af557d5d4efef41f8ccdb8eb3a11d88e1700 Mon Sep 17 00:00:00 2001
From: unknown <mats@mysql.com>
Date: Tue, 9 May 2006 12:30:06 +0200
Subject: [PATCH] Plugging memory leak in row-based replication triggered by
 test rpl_err_ignoredtables.

sql/log_event.cc:
  Clearing tables to lock list in the event of errors.
  Adding asserts to catch failing to clear the list of tables to lock.
  Releasing allocated memory if the table will not be replicated.
sql/rpl_rli.h:
  Adding assert to ensure post-condition of clear_tables_to_lock().
  Minor rewrites.
---
 sql/log_event.cc | 30 +++++++++++++++---------------
 sql/rpl_rli.h    | 11 +++++------
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/sql/log_event.cc b/sql/log_event.cc
index d51a0ef4c9f..e958056291f 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5350,6 +5350,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
         slave_print_msg(ERROR_LEVEL, rli, error,
                         "Error in %s event: when locking tables",
                         get_type_str());
+        rli->clear_tables_to_lock();
         DBUG_RETURN(error);
       }
 
@@ -5385,6 +5386,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
                            "unexpected success or fatal error"));
           thd->query_error= 1;
         }
+        rli->clear_tables_to_lock();
         DBUG_RETURN(error);
       }
     }
@@ -5393,19 +5395,17 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
       the table map and remove them from tables to lock.
      */
     
-    TABLE_LIST *ptr= rli->tables_to_lock;
-    while (ptr)
+    TABLE_LIST *ptr;
+    for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
     {
       rli->m_table_map.set_table(ptr->table_id, ptr->table);
       rli->touching_table(ptr->db, ptr->table_name, ptr->table_id);
-      char *to_free= reinterpret_cast<char*>(ptr);
-      ptr= ptr->next_global;
-      my_free(to_free, MYF(MY_WME));
     }
-    rli->tables_to_lock= 0;
-    rli->tables_to_lock_count= 0;
+    rli->clear_tables_to_lock();
   }
 
+  DBUG_ASSERT(rli->tables_to_lock == NULL && rli->tables_to_lock_count == 0);
+
   TABLE* table= rli->m_table_map.get_table(m_table_id);
 
   if (table)
@@ -5816,12 +5816,8 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
                     &tname_mem, NAME_LEN + 1,
                     NULL);
 
-  /*
-    If memory is allocated, it the pointer to it should be stored in
-    table_list.  If this is not true, the memory will not be correctly
-    free:ed later.
-  */
-  DBUG_ASSERT(memory == NULL || memory == table_list);
+  if (memory == NULL)
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
   uint32 dummy_len;
   bzero(table_list, sizeof(*table_list));
@@ -5836,8 +5832,12 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
 
   int error= 0;
 
-  if (rpl_filter->db_ok(table_list->db) &&
-      (!rpl_filter->is_on() || rpl_filter->tables_ok("", table_list)))
+  if (!rpl_filter->db_ok(table_list->db) ||
+      (rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list)))
+  {
+    my_free((gptr) memory, MYF(MY_WME));
+  }
+  else
   {
     /*
       Check if the slave is set to use SBR.  If so, it should switch
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index cacae1aa4c2..99606353080 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -309,15 +309,14 @@ typedef struct st_relay_log_info
 
   void cleanup_context(THD *, bool);
   void clear_tables_to_lock() {
-    TABLE_LIST *ptr= tables_to_lock;
-    while (ptr)
+    while (tables_to_lock)
     {
-      char *to_free= reinterpret_cast<char*>(ptr);
-      ptr= ptr->next_global;
+      char *to_free= reinterpret_cast<gptr>(tables_to_lock);
+      tables_to_lock= tables_to_lock->next_global;
+      tables_to_lock_count--;
       my_free(to_free, MYF(MY_WME));
     }
-    tables_to_lock= 0;
-    tables_to_lock_count= 0;
+    DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
   }
 
   time_t unsafe_to_stop_at;
-- 
2.30.9