Comment 32 for bug 1042946

Possible source of the leak is in following lines:
slave.cc, exec_relay_log_event:

    if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT &&
        !rli->is_deferred_event(ev))
    {
      DBUG_PRINT("info", ("Deleting the event after it has been executed"));
      delete ev;
    }

Deferred events are Int-, Rand- and User- var events. However above code *COULD* skip deletion of another types of events *WITHOUT* adding them to deferred_events container, i.e. these events eventually will not be deleted and memory will leak. The reason is implementation of is_deferred_event:
  /*
     Returns true if the argument event resides in the containter;
     more specifically, the checking is done against the last added event.
  */
  bool is_deferred_event(Log_event * ev)
  {
    return deferred_events_collecting ? deferred_events->is_last(ev) : false;
  };

and
bool is_last(Log_event *ev) { return ev == last_added; };

It just checks whether last added event pointer is equal to pointer to event which was added to container by previous call of Deferred_log_events::add:

int Deferred_log_events::add(Log_event *ev)
{
  last_added= ev;
  insert_dynamic(&array, (uchar*) &ev);
  return 0;
}

as we can see last_added updated correctly.

However deferred_events usage pattern is following:

handle_slave_sql()
{
 rli->deferred_events= new Deferred_log_events(rli);
 while(!killed)
 {
  rli->deferred_events= new Deferred_log_events(rli);
  if (received deferred event ev) {
   rli->deferred_events->add(ev);
  }
  else {
   execute statement
   rli->deferred_events->rewind();
  }
 }
 delete rli->deferred_events;
}

Container constantly filled with events and cleared, filled and cleared again innumerable times. When container cleared in following code:
void Deferred_log_events::rewind()
{
  /*
    Reset preceeding Query log event events which execution was
    deferred because of slave side filtering.
  */
  if (!is_empty())
  {
    for (uint i= 0; i < array.elements; i++)
    {
      Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
      delete ev;
    }
    if (array.elements > array.max_element)
      freeze_size(&array);
    reset_dynamic(&array);
  }
}

last_added still points to already deleted event. Which mean nothing blocks the allocator from allocating memory region with same address (last_added) for the next (unnecessary deferred) event. Which *SURELY* happens innumerable times and leads to memory leaks of pseudo random replication log events.

Suggested patch to fix this is:

=== modified file 'Percona-Server/sql/rpl_utility.cc'
--- Percona-Server/sql/rpl_utility.cc 2012-04-21 10:24:39 +0000
+++ Percona-Server/sql/rpl_utility.cc 2012-12-19 08:58:02 +0000
@@ -1115,6 +1115,7 @@
     if (array.elements > array.max_element)
       freeze_size(&array);
     reset_dynamic(&array);
+ last_added= NULL;
   }
 }