[MDEV-6323] ‘explain_node’ may be used uninitialized in this function Created: 2014-06-10  Updated: 2015-02-25  Resolved: 2015-02-25

Status: Closed
Project: MariaDB Server
Component/s: Optimizer
Affects Version/s: 10.0.11
Fix Version/s: 10.1.3

Type: Bug Priority: Major
Reporter: Sergey Vojtovich Assignee: Sergei Petrunia
Resolution: Fixed Votes: 0
Labels: explain, optimizer

Issue Links:
Relates
relates to MDEV-6314 Compile/run MariaDB with ASan Closed

 Description   

Compiling MariaDB with ASAN gives:
cmake -DWITH_ASAN=ON -DCMAKE_BUILD_TYPE=Debug -DMYSQL_MAINTAINER_MODE=ON

[ 51%] Building CXX object sql/CMakeFiles/sql.dir/sql_select.cc.o
In file included from /home/svoj/devel/maria/10.0/sql/handler.h:34:0,
                 from /home/svoj/devel/maria/10.0/sql/datadict.h:18,
                 from /home/svoj/devel/maria/10.0/sql/table.h:23,
                 from /home/svoj/devel/maria/10.0/sql/field.h:29,
                 from /home/svoj/devel/maria/10.0/sql/unireg.h:172,
                 from /home/svoj/devel/maria/10.0/sql/sql_select.cc:33:
/home/svoj/devel/maria/10.0/sql/sql_array.h: In member function ‘int JOIN::save_explain_data_intern(Explain_query*, bool, bool, bool, const char*)’:
/home/svoj/devel/maria/10.0/sql/sql_array.h:159:38: warning: ‘explain_node’ may be used uninitialized in this function [-Wmaybe-uninitialized]
     return insert_dynamic(&array, &el);
                                      ^
/home/svoj/devel/maria/10.0/sql/sql_select.cc:23218:17: note: ‘explain_node’ was declared here
   Explain_node *explain_node;
                 ^

Please check if there is a real bug here.



 Comments   
Comment by Sergei Petrunia [ 2015-02-19 ]

Looking at where explain_node may be uninitialized.
Added an assert:

    DBUG_ASSERT(join->select_lex != join->unit->fake_select_lex);

and removed the corresponding else-branch. This is useful but doesn't fix the warning.

Comment by Sergei Petrunia [ 2015-02-19 ]

Fixing the warning requires figuring what to do when this else-if branch is not taken:

   else if (!join->select_lex->master_unit()->derived ||
            join->select_lex->master_unit()->derived->is_materialized_derived())

Comment by Sergei Petrunia [ 2015-02-19 ]

Trying to find when this tescase fails.. the following testcase crashes the ASAN build, but not the regular debug build:

--source include/have_innodb.inc
create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
 
CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a));
INSERT INTO t1 VALUES (1,2), (2,3), (3,4), (4,5), (5,10);
CREATE TABLE t2 (x INT);
INSERT INTO t2 VALUES (1), (2), (3), (4);
CREATE VIEW v2 (a,c) AS SELECT a, b+1 FROM t1 where b+1 < (select max(a) from ten);
EXPLAIN DELETE v2 FROM t2, v2 WHERE t2.x = v2.a;

... and it's not clear why the regular build doesn't crash. They seem to be taking different execution path when they are optimized.

Comment by Sergei Petrunia [ 2015-02-19 ]

... No, the crash goes away with the latest tree. The warning is still there.

Comment by Sergei Petrunia [ 2015-02-20 ]

Getting back to the question of what are the cases where this else-if branch is not taken:

  else if (!join->select_lex->master_unit()->derived ||
            join->select_lex->master_unit()->derived->is_materialized_derived())

Running mtr yielded this example:

CREATE TABLE t1 (a INT);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (1), (2), (3);
CREATE VIEW v1 (x) AS SELECT b FROM t2;
explain INSERT INTO v1 SELECT * FROM t1;

JOIN::optimize and JOIN::save_explain_data_intern are invoked for the view (it has select_lex->select_number=2).

Comment by Sergei Petrunia [ 2015-02-20 ]

It happens here:

  #0  JOIN::optimize (this=this@entry=0x607200225f60) at /home/psergey/dev-git/10.0/sql/sql_select.cc:1022
  #1  0x00000000007d050b in mysql_select (thd=thd@entry=0x608600037270, rref_pointer_array=rref_pointer_array@entry=0x6072002087b8, tables=<optimized out>, wild_num=<optimized out>, fields=..., conds=<optimized out>, og_num=<optimized out>, og_num@entry=0, order=<optimized out>, group=<optimized out>, having=<optimized out>, proc_param=<optimized out>, proc_param@entry=0x0, select_options=<optimized out>, select_options@entry=2147748612, result=<optimized out>, result@entry=0x607200210600, unit=<optimized out>, unit@entry=0x607200207e50, select_lex=<optimized out>, select_lex@entry=0x607200208540) at /home/psergey/dev-git/10.0/sql/sql_select.cc:3296
  #2  0x00000000007d171d in mysql_explain_union (thd=thd@entry=0x608600037270, unit=unit@entry=0x607200207e50, result=result@entry=0x607200210600) at /home/psergey/dev-git/10.0/sql/sql_select.cc:23995
  #3  0x00000000007d1ade in select_describe (join=join@entry=0x607200209178, need_tmp_table=<optimized out>, need_order=<optimized out>, distinct=<optimized out>, message=<optimized out>) at /home/psergey/dev-git/10.0/sql/sql_select.cc:23952
  #4  0x00000000007d3570 in JOIN::exec_inner (this=this@entry=0x607200209178) at /home/psergey/dev-git/10.0/sql/sql_select.cc:2568
  #5  0x00000000007da8a3 in JOIN::exec (this=this@entry=0x607200209178) at /home/psergey/dev-git/10.0/sql/sql_select.cc:2370
  #6  0x00000000007d068e in mysql_select (thd=thd@entry=0x608600037270, rref_pointer_array=rref_pointer_array@entry=0x60860003b8e8, tables=<optimized out>, wild_num=<optimized out>, fields=..., conds=<optimized out>, og_num=<optimized out>, order=<optimized out>, order@entry=0x0, group=<optimized out>, having=<optimized out>, proc_param=<optimized out>, proc_param@entry=0x0, select_options=<optimized out>, select_options@entry=3489925892, result=<optimized out>, result@entry=0x607200210600, unit=<optimized out>, unit@entry=0x60860003af80, select_lex=<optimized out>, select_lex@entry=0x60860003b670) at /home/psergey/dev-git/10.0/sql/sql_select.cc:3310
  #7  0x00000000007d0c84 in handle_select (thd=thd@entry=0x608600037270, lex=lex@entry=0x60860003aeb8, result=result@entry=0x607200210600, setup_tables_done_option=setup_tables_done_option@entry=1073741824) at /home/psergey/dev-git/10.0/sql/sql_select.cc:373

Going up, we see that select_describe() calls mysql_explain_union for the VIEW here:

    /* 
      Display subqueries only if they are not parts of eliminated WHERE/ON
      clauses.
    */
    if (!(unit->item && unit->item->eliminated))
    {
      if (mysql_explain_union(thd, unit, result))
        DBUG_VOID_RETURN;
    }

I think we should not try to run JOIN::optimize() on a VIEW that has been merged.

I suppose, it is important that the statement is INSERT ... SELECT. This is a case of special kind of VIEW merging. Need to discuss this with sanja.

Comment by Sergei Petrunia [ 2015-02-20 ]

Btw, the problem is only with EXPLAIN, the statement

INSERT INTO v1 SELECT * FROM t1;

does not call JOIN::optimize for the VIEW's select.

Comment by Sergei Petrunia [ 2015-02-24 ]

How to tell if this is a derived table that's "merged for INSERT":

  Breakpoint 1, select_describe (join=0x7fffb4057ee8, need_tmp_table=false, need_order=false, distinct=false, message=0x0) at /home/psergey/dev-git/10.0/sql/sql_select.cc:23962
 
(gdb) p unit->derived
  $1 = (TABLE_LIST *) 0x7fffb4004f60
(gdb) p unit->derived->alias
  $2 = 0x7fffb4004f58 "v1"
(gdb) p unit->derived->merged_for_insert
  $3 = true

Comment by Sergei Petrunia [ 2015-02-25 ]

Developed a fix, against 10.0 tree. I am hesitant to push it into 10.0, though, as the fix doesn't fix any user-visible effect. It only makes the compiler warning go away, and makes the code cleaner.

Interestingly, 10.1 has the same code, but ASAN doesn't produce the warning there. It doesn't produce it even if I take the g++ command line from 10.0 and compile sql_select.cc in 10.1 with it. Instead, it produces warnings in LooseScan code (which is most likely the same between 10.0 and 10.1, too. And I dont get the warnings in LooseScan code in 10.0).

Comment by Sergei Petrunia [ 2015-02-25 ]

Considering the above, I will still push the fix into 10.1 but not into 10.0

Generated at Thu Feb 08 07:11:01 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.