[MDEV-32320] Server crashes at TABLE::add_tmp_key Created: 2023-09-30  Updated: 2023-12-15  Resolved: 2023-10-15

Status: Closed
Project: MariaDB Server
Component/s: Optimizer
Affects Version/s: 10.4, 10.5, 10.6, 10.9, 10.10, 10.11, 11.0, 11.1, 11.2, 11.1.2, 11.2.1
Fix Version/s: 10.4.32, 10.5.23, 10.6.16, 10.10.7, 10.11.6, 11.0.4, 11.1.3

Type: Bug Priority: Major
Reporter: Jingzhou Fu Assignee: Sergei Petrunia
Resolution: Fixed Votes: 0
Labels: None
Environment:

Ubuntu 20.04 x86-64, docker image mariadb:11.1.2



 Description   

PoC:

SELECT 
  EXISTS ( 
    WITH x ( x ) AS ( SELECT 1 ) 
    SELECT NULL 
    WHERE ( 1 , 1 ) = 
         ( SELECT 
           1 , ( ( x , 1.000000 ) , 1 ) 
           IN 
           (SELECT 'x' , 'x' 
            WHERE ( ( 'x' ) ) 
            UNION 
            SELECT 1 , x 
            HAVING 1 != 1 
           )
           FROM x 
          ) 
  );

docker log:

mariadbd(my_print_stacktrace+0x32)[0x55ab626be7c2]
mariadbd(handle_fatal_signal+0x488)[0x55ab62197cf8]
/lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7fe667658520]
mariadbd(_ZN5TABLE11add_tmp_keyEjjPFjPhES0_b+0x1bc)[0x55ab620253ec]
mariadbd(_ZN25Expression_cache_tmptable4initEv+0x1d3)[0x55ab620a3a73]
mariadbd(_ZN18Item_cache_wrapper11check_cacheEv+0x21)[0x55ab621c4aa1]
mariadbd(_ZN18Item_cache_wrapper7val_intEv+0x21)[0x55ab621c4c31]
mariadbd(_ZN14Item_cache_int11cache_valueEv+0x29)[0x55ab621ad149]
mariadbd(_ZN26select_singlerow_subselect9send_dataER4ListI4ItemE+0x3f)[0x55ab61ec193f]
mariadbd(+0x89bf74)[0x55ab61f8df74]
mariadbd(_ZN4JOIN10exec_innerEv+0x1222)[0x55ab61fa6e12]
mariadbd(_ZN4JOIN4execEv+0x3f)[0x55ab61fa6fff]
mariadbd(_ZN30subselect_single_select_engine4execEv+0x146)[0x55ab622777f6]
mariadbd(_ZN14Item_subselect4execEv+0x4c)[0x55ab6227673c]
mariadbd(_ZN24Item_singlerow_subselect11bring_valueEv+0x17)[0x55ab62277ec7]
mariadbd(_ZN14Arg_comparator11compare_rowEv+0x37)[0x55ab621d1377]
mariadbd(_ZN12Item_func_eq7val_intEv+0x2f)[0x55ab621d164f]
mariadbd(_ZN4JOIN10exec_innerEv+0x432)[0x55ab61fa6022]
mariadbd(_ZN4JOIN4execEv+0x3f)[0x55ab61fa6fff]
mariadbd(_ZN30subselect_single_select_engine4execEv+0x146)[0x55ab622777f6]
mariadbd(_ZN14Item_subselect4execEv+0x4c)[0x55ab6227673c]
mariadbd(_ZN21Item_exists_subselect7val_intEv+0x23)[0x55ab622764a3]
mariadbd(_ZNK12Type_handler14Item_send_longEP4ItemP8ProtocolP8st_value+0x1d)[0x55ab620ee89d]
mariadbd(_ZN8Protocol19send_result_set_rowEP4ListI4ItemE+0xea)[0x55ab61e4ccfa]
mariadbd(_ZN11select_send9send_dataER4ListI4ItemE+0x37)[0x55ab61ecb6a7]
mariadbd(_ZN4JOIN10exec_innerEv+0xc90)[0x55ab61fa6880]
mariadbd(_ZN4JOIN4execEv+0x3f)[0x55ab61fa6fff]
mariadbd(_Z12mysql_selectP3THDP10TABLE_LISTR4ListI4ItemEPS4_jP8st_orderS9_S7_S9_yP13select_resultP18st_select_lex_unitP13st_select_lex+0x12c)[0x55ab61fa4f7c]
mariadbd(_Z13handle_selectP3THDP3LEXP13select_resulty+0x154)[0x55ab61fa5774]
mariadbd(+0x826f55)[0x55ab61f18f55]
mariadbd(_Z21mysql_execute_commandP3THDb+0x419e)[0x55ab61f27f0e]
mariadbd(_Z11mysql_parseP3THDPcjP12Parser_state+0x1e7)[0x55ab61f29237]
mariadbd(_Z16dispatch_command19enum_server_commandP3THDPcjb+0x14bd)[0x55ab61f2ba1d]
mariadbd(_Z10do_commandP3THDb+0x138)[0x55ab61f2d818]
mariadbd(_Z24do_handle_one_connectionP7CONNECTb+0x3bf)[0x55ab620553af]
mariadbd(handle_one_connection+0x5d)[0x55ab620556fd]
mariadbd(+0xcd1906)[0x55ab623c3906]
/lib/x86_64-linux-gnu/libc.so.6(+0x94b43)[0x7fe6676aab43]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x44)[0x7fe66773bbb4]
 
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (0x7fe5f80130d8): SELECT EXISTS ( WITH x ( x ) AS ( SELECT 1 ) SELECT NULL WHERE ( 1 , 1 ) = ( SELECT 1 , ( ( x , 1.000000 ) , 1 ) IN ( SELECT 'x' , 'x' WHERE ( ( 'x' ) ) UNION SELECT 1 , x HAVING 1 != 1 ) FROM x ) )
 
Connection ID (thread ID): 4
Status: NOT_KILLED
 
Optimizer switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=on



 Comments   
Comment by Alice Sherepa [ 2023-10-09 ]

Thanks! I repeated on 10.4-11.2:

SELECT  ( ( x , 1 ) , 1 ) IN ( SELECT 'x' , 'x'  WHERE 0 UNION SELECT 1 , x HAVING 0) FROM  ( SELECT 1 x ) x ;

Version: '10.4.32-MariaDB-debug-log'  
231009 15:22:32 [ERROR] mysqld got signal 11 ;
 
Server version: 10.4.32-MariaDB-debug-log source revision: 0c7af6a2a19343cb9d4fedbd7165b8f73bc4cf96
 
sigaction.c:0(__restore_rt)[0x7f0ec71dc420]
sql/sql_bitmap.h:118(Bitmap<64u>::set_bit(unsigned int))[0x55de76e6efa3]
sql/table.cc:7984(TABLE::add_tmp_key(unsigned int, unsigned int, unsigned int (*)(unsigned char*), unsigned char*, bool))[0x55de77317475]
sql/sql_expression_cache.cc:143(Expression_cache_tmptable::init())[0x55de774e68c2]
sql/item.cc:8638(Item_cache_wrapper::init_on_demand())[0x55de77825e89]
sql/item.cc:8761(Item_cache_wrapper::check_cache())[0x55de77826cc0]
sql/item.cc:8824(Item_cache_wrapper::val_int())[0x55de778277e6]
sql/sql_type.cc:7106(Type_handler::Item_send_long(Item*, Protocol*, st_value*) const)[0x55de7755a330]
sql/sql_type.h:5192(Type_handler_long::Item_send(Item*, Protocol*, st_value*) const)[0x55de77574a3c]
sql/item.h:1045(Item::send(Protocol*, st_value*))[0x55de76d0c5e4]
sql/item.cc:8682(Item_cache_wrapper::send(Protocol*, st_value*))[0x55de77826484]
sql/protocol.cc:1038(Protocol::send_result_set_row(List<Item>*))[0x55de76cfdf63]
sql/sql_class.cc:3138(select_send::send_data(List<Item>&))[0x55de76eb0d83]
sql/sql_select.cc:22098(end_send(JOIN*, st_join_table*, bool))[0x55de7712150b]
sql/sql_select.cc:20363(do_select(JOIN*, Procedure*))[0x55de77115869]
sql/sql_select.cc:4605(JOIN::exec_inner())[0x55de770a3adc]
sql/sql_select.cc:4388(JOIN::exec())[0x55de770a110c]
sql/sql_select.cc:4828(mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*))[0x55de770a52e8]
sql/sql_select.cc:442(handle_select(THD*, LEX*, select_result*, unsigned long))[0x55de77075de0]
sql/sql_parse.cc:6475(execute_sqlcom_select(THD*, TABLE_LIST*))[0x55de76fe1be4]
sql/sql_parse.cc:3978(mysql_execute_command(THD*))[0x55de76fcf35b]
sql/sql_parse.cc:8012(mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool))[0x55de76feb0bf]
sql/sql_parse.cc:1860(dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool))[0x55de76fc14e5]
sql/sql_parse.cc:1378(do_command(THD*))[0x55de76fbe010]
sql/sql_connect.cc:1420(do_handle_one_connection(CONNECT*))[0x55de773cbdeb]
sql/sql_connect.cc:1325(handle_one_connection)[0x55de773cb68f]
perfschema/pfs.cc:1871(pfs_spawn_thread)[0x55de78076274]
nptl/pthread_create.c:478(start_thread)[0x7f0ec71d0609]
 
Query (0x62b0000a1420): SELECT  ( ( x , 1 ) , 1 ) IN ( SELECT 'x' , 'x'  WHERE 0 UNION SELECT 1 , x HAVING 0) FROM  ( SELECT 1 x ) x

Comment by Sergei Petrunia [ 2023-10-12 ]

Execution eventually reaches

  #0  Expression_cache_tmptable::init (this=0x7fff78093b10) at /home/psergey/dev-git2/10.4-fix1/sql/sql_expression_cache.cc:121

The list of items passed to create_tmp_table is:

(gdb) p dbug_print_item(items.elem(0))
  $125 = 0x5555577d6c80 <dbug_item_print_buf> "<cache>(<in_optimizer>(((1,1.000000),1),<exists>(subquery#5)))"
(gdb) p dbug_print_item(items.elem(1))
  $126 = 0x5555577d6c80 <dbug_item_print_buf> "(1,1.000000)"
(gdb) p dbug_print_item(items.elem(2))
  $127 = 0x5555577d6c80 <dbug_item_print_buf> "1"
(gdb) p dbug_print_item(items.elem(3))
  $128 = 0x5555577d6c80 <dbug_item_print_buf> "1"
(gdb) p items.elements
  $129 = 4

create_tmp_field() returns NULL for Item_row, the "(1,1.000000)" .

This means, the temptable is created with 3 fields, not 4.

Then add_tmp_key() crashes when it tries to add an index on fields with indexes 1,2,and 3. (field with index 0 is subquery's result).

Comment by Sergei Petrunia [ 2023-10-12 ]

( ( x , 1.000000 ) , 1 ) 
IN 
(SELECT 
   'x' , 'x' 
 WHERE ( ( 'x' ) ) 
 UNION 
 SELECT 1 , x 
 HAVING 1 != 1 
)

( x , 1.000000 ) is not a scalar here ... should this have produced an error on name resolution phase?

Comment by Sergei Petrunia [ 2023-10-12 ]

A smaller testcase:

select
  ( ( 'x' , 1.000000 ) , 1 ) 
IN 
(SELECT 
   'x' , 'x' 
 WHERE ( 'x' ) 
 UNION 
 SELECT 1 , 'x' 
 HAVING 1 != 1 
) as T;

Doesn't produce an error. It produces:

+------+
| T    |
+------+
|    0 |
+------+
1 row in set, 1 warning (0.000 sec)

MariaDB [test]> show warnings;
+---------+------+---------------------------------------+
| Level   | Code | Message                               |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'x' |
+---------+------+---------------------------------------+
1 row in set (0.000 sec)

Comment by Sergei Petrunia [ 2023-10-12 ]

If I change the query in any way, e.g.

  WHERE ( 'x' ) 

to WHERE 1, I get the correct result:

ERROR 1241 (21000): Operand should contain 2 column(s)

Comment by Sergei Petrunia [ 2023-10-12 ]

In the failing query:

JOIN::choose_tableless_subquery_plan() is called with select_number=2.
It reaches this point:

          /*
            Both group by queries and non-group by queries without aggregate
            functions produce empty subquery result. There is no need to further
            rewrite the subquery because it will not be executed at all.
          */
          exec_const_cond= 0;
=>        return FALSE;

It does NOT reach these lines:

        if (in_subs->create_in_to_exists_cond(this) ||
            in_subs->inject_in_to_exists_cond(this))

While for the subquery with WHERE 1 is does reach them, and we get here:

        if (select_lex->ref_pointer_array[i]->
=>          check_cols(left_expr->element_index(i)->cols()))

in here:

  #0  my_error (nr=1241, MyFlags=0) at /home/psergey/dev-git2/10.4-fix1/mysys/my_error.c:109
  #1  0x00005555560fe14e in Item::check_cols (this=0x7fff74016498, c=2) at /home/psergey/dev-git2/10.4-fix1/sql/item.cc:953
  #2  0x00005555561ca1ac in Item_in_subselect::create_row_in_to_exists_cond (this=0x7fff74017d00, join=0x7fff74019468, where_item=0x7fff74019968, having_item=0x7ff
  #3  0x00005555561cb8ad in Item_in_subselect::create_in_to_exists_cond (this=0x7fff74017d00, join_arg=0x7fff74019468) at /home/psergey/dev-git2/10.4-fix1/sql/item
  #4  0x0000555555f9aa11 in JOIN::choose_tableless_subquery_plan (this=0x7fff74019468) at /home/psergey/dev-git2/10.4-fix1/sql/opt_subselect.cc:6763

Comment by Sergei Petrunia [ 2023-10-13 ]

bb-10.4-MDEV-32320. sanja_byelkin, please review.

Comment by Oleksandr Byelkin [ 2023-10-13 ]

OK to push

Generated at Thu Feb 08 10:30:28 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.