• Guilhem Bichot's avatar
    Fix for Bug#16614004 CRASH AFTER READING FREED MEMORY AFTER DOING DDL IN STORED ROUTINE · 992a6630
    Guilhem Bichot authored
    Inside a loop in a stored procedure, we create a partitioned
    table. The CREATE statement is thus treated as a prepared statement:
    it is prepared once, and then executed by each iteration. Thus its Lex
    is reused many times. This Lex contains a part_info member, which
    describes how the partitions should be laid out, including the
    partitioning function. Each execution of the CREATE does this, in
    open_table_from_share ():
    
        tmp= mysql_unpack_partition(thd, share->partition_info_str,
                                    share->partition_info_str_len,
                                    outparam, is_create_table,
                                    share->default_part_db_type,
                                    &work_part_info_used);
     ...
          tmp= fix_partition_func(thd, outparam, is_create_table);
    The first line calls init_lex_with_single_table() which creates
    a TABLE_LIST, necessary for the "field fixing" which will be
    done by the second line; this is how it is created:
      if ((!(table_ident= new Table_ident(thd,
                                          table->s->db,
                                          table->s->table_name, TRUE))) ||
          (!(table_list= select_lex->add_table_to_list(thd,
                                                       table_ident,
                                                       NULL,
                                                       0))))
        return TRUE;
    it is allocated in the execution memory root.
    Then the partitioning function ("id", stored in Lex -> part_info)
    is fixed, which calls Item_ident:: fix_fields (), which resolves
    "id" to the table_list above, and stores in the item's
    cached_table a pointer to this table_list. 
    The table is created, later it is dropped by another statement,
    then we execute again the prepared CREATE. This reuses the Lex,
    thus also its part_info, thus also the item representing the
    partitioning function (part_info is cloned but it's a shallow
    cloning); CREATE wants to fix the item again (which is
    normal, every execution fixes items again), fix_fields ()
    sees that the cached_table pointer is set and picks up the
    pointed table_list. But this last object does not exist
    anymore (it was allocated in the execution memory root of
    the previous execution, so it has been freed), so we access
    invalid memory.
    The solution: when creating the table_list, mark that it
    cannot be cached.
    992a6630
sql_partition.cc 275 KB