• kostja@bodhi.local's avatar
    A fix for Bug#26750 "valgrind leak in sp_head" (and post-review · 86f02cd3
    kostja@bodhi.local authored
    fixes).
    
    The legend: on a replication slave, in case a trigger creation
    was filtered out because of application of replicate-do-table/
    replicate-ignore-table rule, the parsed definition of a trigger was not 
    cleaned up properly. LEX::sphead member was left around and leaked 
    memory. Until the actual implementation of support of 
    replicate-ignore-table rules for triggers by the patch for Bug 24478 it 
    was never the case that "case SQLCOM_CREATE_TRIGGER"
    was not executed once a trigger was parsed,
    so the deletion of lex->sphead there worked and the memory did not leak.
    
    The fix: 
    
    The real cause of the bug is that there is no 1 or 2 places where
    we can clean up the main LEX after parse. And the reason we 
    can not have just one or two places where we clean up the LEX is
    asymmetric behaviour of MYSQLparse in case of success or error. 
    
    One of the root causes of this behaviour is the code in Item::Item()
    constructor. There, a newly created item adds itself to THD::free_list
    - a single-linked list of Items used in a statement. Yuck. This code
    is unaware that we may have more than one statement active at a time,
    and always assumes that the free_list of the current statement is
    located in THD::free_list. One day we need to be able to explicitly
    allocate an item in a given Query_arena.
    Thus, when parsing a definition of a stored procedure, like
    CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
    we actually need to reset THD::mem_root, THD::free_list and THD::lex
    to parse the nested procedure statement (SELECT *).
    The actual reset and restore is implemented in semantic actions
    attached to sp_proc_stmt grammar rule.
    The problem is that in case of a parsing error inside a nested statement
    Bison generated parser would abort immediately, without executing the
    restore part of the semantic action. This would leave THD in an 
    in-the-middle-of-parsing state.
    This is why we couldn't have had a single place where we clean up the LEX
    after MYSQLparse - in case of an error we needed to do a clean up
    immediately, in case of success a clean up could have been delayed.
    This left the door open for a memory leak.
    
    One of the following possibilities were considered when working on a fix:
    - patch the replication logic to do the clean up. Rejected
    as breaks module borders, replication code should not need to know the
    gory details of clean up procedure after CREATE TRIGGER.
    - wrap MYSQLparse with a function that would do a clean up.
    Rejected as ideally we should fix the problem when it happens, not
    adjust for it outside of the problematic code.
    - make sure MYSQLparse cleans up after itself by invoking the clean up
    functionality in the appropriate places before return. Implemented in 
    this patch.
    - use %destructor rule for sp_proc_stmt to restore THD - cleaner
    than the prevoius approach, but rejected
    because needs a careful analysis of the side effects, and this patch is 
    for 5.0, and long term we need to use the next alternative anyway
    - make sure that sp_proc_stmt doesn't juggle with THD - this is a 
    large work that will affect many modules.
    
    Cleanup: move main_lex and main_mem_root from Statement to its
    only two descendants Prepared_statement and THD. This ensures that
    when a Statement instance was created for purposes of statement backup,
    we do not involve LEX constructor/destructor, which is fairly expensive.
    In order to track that the transformation produces equivalent 
    functionality please check the respective constructors and destructors
    of Statement, Prepared_statement and THD - these members were
    used only there.
    This cleanup is unrelated to the patch.
    86f02cd3
sql_lex.h 40 KB