• Sujatha Sivakumar's avatar
    MDEV-17260: Memory leaks in mysqlbinlog · 9a5a86f2
    Sujatha Sivakumar authored
    Problem:
    ========
    The mysqlbinlog tool is leaking memory, causing failures in various tests when
    compiling and testing with AddressSanitizer or LeakSanitizer like this:
    
    cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_ASAN:BOOL=ON /path/to/source
    make -j$(nproc)
    cd mysql-test
    ASAN_OPTIONS=abort_on_error=1 ./mtr --parallel=auto
    
    Analysis:
    =========
    Two types of leaks were observed during above execution.
    
    1) Leak in Log_event::read_log_event(char const*, unsigned int, char const**,
       Format_description_log_event const*, char)
       File: sql/log_event.cc:2150
    
    For all row based replication events the memory which is allocated during
    read_log_event is not freed after the event is processed. The event specific
    memory has to be retained only when flashback option is enabled with
    mysqlbinlog tool. In this case all the events are retained till the end
    statement is received and they are processed in reverse order and they are
    destroyed. But in the existing code all events are retained irrespective of
    flashback mode. Hence the memory leaks are observed.
    
    2) read_remote_annotate_event(unsigned char*, unsigned long, char const**)
       File: client/mysqlbinlog.cc:194
    
    In general the Annotate event is not printed immediately because all
    subsequent rbr-events can be filtered away. Instead it will be printed
    together with the first not filtered away Table map or the last rbr will be
    processed. While reading remote annotate events memory is allocated for event
    buffer and event's temp_buf is made to point to the allocated buffer as shown
    below.  The TRUE flag is used for doing proper cleanup using free_temp_buf().
    i.e at the time of deletion of annotate event its destructor takes care of
    clearing the temp_buf.
    
    /*
      Ensure the event->temp_buf is pointing to the allocated buffer.
      (TRUE = free temp_buf on the event deletion)
    */
     event->register_temp_buf((char*)event_buf, TRUE);
    
    But existing code does the following when it receives a remote annotate_event.
    
    if (remote_opt)
      ev->temp_buf= 0;
    
    That is code immediately sets temp_buf=0, because of which free_temp_buf()
    call will return empty handed as it has lost the reference to the allocated
    temporary buffer. This results in memory leak
    
    Fix:
    ====
    1) If not in flashback mode, destroy the memory for events once they are
    processed.
    
    2) Remove the ev->temp_buf=0 code for remote option. Let the proper cleanup to
    be done as part of free_temp_buf().
    9a5a86f2
flashback.test 10.5 KB