|
ASAN Sees use-after-poison
|
10.11.0 fe1f8f2c6b6f3b8e3383168225f9ae7853028947 (Optimized, UBASAN)
|
==3243144==ERROR: AddressSanitizer: use-after-poison on address 0x6290000887b0 at pc 0x55f7a34ef836 bp 0x14cfbfdb91e0 sp 0x14cfbfdb91d0
|
READ of size 8 at 0x6290000887b0 thread T16
|
#0 0x55f7a34ef835 in base_list_iterator::next() /test/10.11_opt_san/sql/sql_list.h:431
|
#1 0x55f7a34ef835 in List_iterator<Item>::operator++(int) /test/10.11_opt_san/sql/sql_list.h:596
|
#2 0x55f7a34ef835 in subquery_types_allow_materialization /test/10.11_opt_san/sql/opt_subselect.cc:888
|
#3 0x55f7a34f069a in is_materialization_applicable(THD*, Item_in_subselect*, st_select_lex*) /test/10.11_opt_san/sql/opt_subselect.cc:521
|
#4 0x55f7a34f2d25 in check_and_do_in_subquery_rewrites(JOIN*) /test/10.11_opt_san/sql/opt_subselect.cc:755
|
#5 0x55f7a2db7f6e in JOIN::prepare(TABLE_LIST*, Item*, unsigned int, st_order*, bool, st_order*, Item*, st_order*, st_select_lex*, st_select_lex_unit*) /test/10.11_opt_san/sql/sql_select.cc:1556
|
#6 0x55f7a48acec4 in subselect_single_select_engine::prepare(THD*) /test/10.11_opt_san/sql/item_subselect.cc:3930
|
#7 0x55f7a48a5ad5 in Item_subselect::fix_fields(THD*, Item**) /test/10.11_opt_san/sql/item_subselect.cc:295
|
#8 0x55f7a48a8d3c in Item_in_subselect::fix_fields(THD*, Item**) /test/10.11_opt_san/sql/item_subselect.cc:3589
|
#9 0x55f7a2bacd1e in Item::fix_fields_if_needed(THD*, Item**) /test/10.11_opt_san/sql/item.h:1144
|
#10 0x55f7a2bacd1e in Item::fix_fields_if_needed_for_scalar(THD*, Item**) /test/10.11_opt_san/sql/item.h:1148
|
#11 0x55f7a2bacd1e in Item::fix_fields_if_needed_for_order_by(THD*, Item**) /test/10.11_opt_san/sql/item.h:1156
|
#12 0x55f7a2bacd1e in find_order_in_list /test/10.11_opt_san/sql/sql_select.cc:25677
|
#13 0x55f7a2cb5e34 in setup_order(THD*, Bounds_checked_array<Item*>, TABLE_LIST*, List<Item>&, List<Item>&, st_order*, bool) /test/10.11_opt_san/sql/sql_select.cc:25724
|
#14 0x55f7a2db5b3d in setup_without_group /test/10.11_opt_san/sql/sql_select.cc:900
|
#15 0x55f7a2db5b3d in JOIN::prepare(TABLE_LIST*, Item*, unsigned int, st_order*, bool, st_order*, Item*, st_order*, st_select_lex*, st_select_lex_unit*) /test/10.11_opt_san/sql/sql_select.cc:1456
|
#16 0x55f7a2dc3fd6 in mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) /test/10.11_opt_san/sql/sql_select.cc:5045
|
#17 0x55f7a30ea947 in mysql_multi_update(THD*, TABLE_LIST*, List<Item>*, List<Item>*, Item*, unsigned long long, enum_duplicates, bool, st_select_lex_unit*, st_select_lex*, multi_update**) /test/10.11_opt_san/sql/sql_update.cc:1980
|
#18 0x55f7a2a1faa5 in mysql_execute_command(THD*, bool) /test/10.11_opt_san/sql/sql_parse.cc:4487
|
#19 0x55f7a29a4500 in mysql_parse(THD*, char*, unsigned int, Parser_state*) /test/10.11_opt_san/sql/sql_parse.cc:8035
|
#20 0x55f7a29f90ff in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) /test/10.11_opt_san/sql/sql_parse.cc:1894
|
#21 0x55f7a2a043fd in do_command(THD*, bool) /test/10.11_opt_san/sql/sql_parse.cc:1407
|
#22 0x55f7a32ed4cd in do_handle_one_connection(CONNECT*, bool) /test/10.11_opt_san/sql/sql_connect.cc:1418
|
#23 0x55f7a32efb3c in handle_one_connection /test/10.11_opt_san/sql/sql_connect.cc:1312
|
#24 0x14cfe2fe1608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477
|
#25 0x14cfe2256132 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x11f132)
|
|
0x6290000887b0 is located 5552 bytes inside of 16400-byte region [0x629000087200,0x62900008b210)
|
allocated by thread T16 here:
|
#0 0x55f7a2178a08 in __interceptor_malloc (/test/UBASAN_MD010922-mariadb-10.11.0-linux-x86_64-opt/bin/mariadbd+0x79c3a08)
|
#1 0x55f7a6668824 in my_malloc /test/10.11_opt_san/mysys/my_malloc.c:90
|
#2 0x55f7a6644600 in root_alloc /test/10.11_opt_san/mysys/my_alloc.c:66
|
#3 0x55f7a6644600 in reset_root_defaults /test/10.11_opt_san/mysys/my_alloc.c:243
|
#4 0x55f7a269663c in THD::init_for_queries() /test/10.11_opt_san/sql/sql_class.cc:1385
|
#5 0x55f7a32e7ee3 in prepare_new_connection_state(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1240
|
#6 0x55f7a32e9717 in thd_prepare_connection(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1333
|
#7 0x55f7a32e9717 in thd_prepare_connection(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1322
|
#8 0x55f7a32ec509 in do_handle_one_connection(CONNECT*, bool) /test/10.11_opt_san/sql/sql_connect.cc:1408
|
#9 0x55f7a32efb3c in handle_one_connection /test/10.11_opt_san/sql/sql_connect.cc:1312
|
#10 0x14cfe2fe1608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477
|
|
Thread T16 created by T0 here:
|
#0 0x55f7a20a5a45 in pthread_create (/test/UBASAN_MD010922-mariadb-10.11.0-linux-x86_64-opt/bin/mariadbd+0x78f0a45)
|
#1 0x55f7a21c8f83 in create_thread_to_handle_connection(CONNECT*) /test/10.11_opt_san/sql/mysqld.cc:6018
|
#2 0x55f7a21da00f in handle_accepted_socket(st_mysql_socket, st_mysql_socket) /test/10.11_opt_san/sql/mysqld.cc:6139
|
#3 0x55f7a21db037 in handle_connections_sockets() /test/10.11_opt_san/sql/mysqld.cc:6263
|
#4 0x55f7a21ddf94 in mysqld_main(int, char**) /test/10.11_opt_san/sql/mysqld.cc:5913
|
#5 0x14cfe215b082 in __libc_start_main ../csu/libc-start.c:308
|
|
SUMMARY: AddressSanitizer: use-after-poison /test/10.11_opt_san/sql/sql_list.h:431 in base_list_iterator::next()
|
Shadow bytes around the buggy address:
|
0x0c52800090a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c52800090b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c52800090c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 f7 00 00
|
0x0c52800090d0: f7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c52800090e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
=>0x0c52800090f0: 00 00 00 00 f7 f7[f7]f7 00 00 00 00 00 00 00 00
|
0x0c5280009100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
Shadow byte legend (one shadow byte represents 8 application bytes):
|
Addressable: 00
|
Partially addressable: 01 02 03 04 05 06 07
|
Heap left redzone: fa
|
Freed heap region: fd
|
Stack left redzone: f1
|
Stack mid redzone: f2
|
Stack right redzone: f3
|
Stack after return: f5
|
Stack use after scope: f8
|
Global redzone: f9
|
Global init order: f6
|
Poisoned by user: f7
|
Container overflow: fc
|
Array cookie: ac
|
Intra object redzone: bb
|
ASan internal: fe
|
Left alloca redzone: ca
|
Right alloca redzone: cb
|
Shadow gap: cc
|
|
|
It looks identical to (at least) MDEV-29359.
|
|
Still puzzling over this one. Valgrind tells me this.
==22054== Thread 33:
|
==22054== Invalid read of size 8
|
==22054== at 0x9B88AB: base_list_iterator::next_fast() (sql_list.h:443)
|
==22054== by 0x9F5BB8: List_iterator_fast<Item>::operator++(int) (sql_list.h:620)
|
==22054== by 0xBF8927: JOIN::eval_select_list_used_tables() (sql_select.cc:13203)
|
==22054== by 0xBA0588: JOIN::optimize_inner() (sql_select.cc:2113)
|
==22054== by 0xB9F9ED: JOIN::optimize() (sql_select.cc:1871)
|
==22054== by 0xB063EC: st_select_lex::optimize_unflattened_subqueries(bool) (sql_lex.cc:4905)
|
==22054== by 0xD85DF6: JOIN::optimize_constant_subqueries() (opt_subselect.cc:5689)
|
==22054== by 0xBA09CF: JOIN::optimize_inner() (sql_select.cc:2194)
|
==22054== by 0xB9F9ED: JOIN::optimize() (sql_select.cc:1871)
|
==22054== by 0xBAB5AA: mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (sql_select.cc:5096)
|
==22054== by 0xB9A7D1: handle_select(THD*, LEX*, select_result*, unsigned long long) (sql_select.cc:581)
|
==22054== by 0xB44AEE: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:6263)
|
==22054== Address 0x3b64e958 is 56 bytes inside a block of size 64 alloc'd
|
==22054== at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
|
==22054== by 0x18B620F: my_malloc (my_malloc.c:90)
|
==22054== by 0x18A69D9: alloc_root (my_alloc.c:287)
|
==22054== by 0x9B85EA: Sql_alloc::operator new(unsigned long, st_mem_root*) (sql_alloc.h:37)
|
==22054== by 0x9B87AF: base_list::push_back(void*, st_mem_root*) (sql_list.h:195)
|
==22054== by 0xA05504: List<Item>::push_back(Item*, st_mem_root*) (sql_list.h:505)
|
==22054== by 0xB03607: st_select_lex::add_item_to_list(THD*, Item*) (sql_lex.cc:3473)
|
==22054== by 0xB251F4: add_item_to_list(THD*, Item*) (sql_class.h:7373)
|
==22054== by 0xE47393: MYSQLparse(THD*) (sql_yacc.yy:8958)
|
==22054== by 0xB4EC2B: parse_sql(THD*, Parser_state*, Object_creation_ctx*, bool) (sql_parse.cc:10390)
|
==22054== by 0xB492B8: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:7950)
|
==22054== by 0xB3640D: dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) (sql_parse.cc:1894)
|
==22054==
|
==22054== (action on error) vgdb me ...
|
Which makes no sense at all. It looks like the memory allocation metadata is corrupted.
|
|
Johnston The Valgrind stack matches the ASAN stack for the first two frames. Does the ASAN trace above highlight where the issue is located?
|
|
Whilst the use-after-poison issue was discovered while inside the base_list_iterator class def in sql/sql_list.h (at line 431);
inline void *next(void)
|
{
|
prev=el;
|
current= *el;
|
el= ¤t->next;
|
return current->info; // << Here, line 431
|
}
|
The original memory allocation for this thread was done by thread T16, which was started itself by the main mysqld_main thread (T0), using this code in reset_root_defaults in mysys/my_alloc.c line 243:
/* Allocate new prealloc block and add it to the end of free list */
|
if ((mem= (USED_MEM *) root_alloc(mem_root, size, &alloced_size,
|
MYF(MY_WME))))
|
{
|
mem->size= alloced_size;
|
mem->left= alloced_size - ALIGN_SIZE(sizeof(USED_MEM));
|
mem->next= *prev;
|
*prev= mem_root->pre_alloc= mem;
|
TRASH_MEM(mem);
|
}
|
As per the ASAN trace. However, interestingly, we see this at the top of that code:
#if !(defined(HAVE_valgrind) && defined(EXTRA_DEBUG))
|
Showing that using/not using Valgrind will lead to different outcomes here. Additionally, and a little strange, there is this "in-between" #endif preprocessor directive near the end of the function code block (i.e. is it in the right place?):
}
|
else
|
#endif
|
mem_root->pre_alloc= 0;
|
|
DBUG_VOID_RETURN;
|
}
|
This function in particular (also in combination with having Valgrind turned on/off) may warrant further research.
|
|
inner->max_length in subquery_types_allow_materialization looks to be corrupted
Program terminated with signal SIGSEGV, Segmentation fault.
|
#0 subquery_types_allow_materialization (thd=thd@entry=0x14d220000d48, in_subs=in_subs@entry=0x14d220028708)
|
at /test/10.11_dbg/sql/opt_subselect.cc:891
|
891 total_key_length += inner->max_length;
|
[Current thread is 1 (Thread 0x14d2690c4700 (LWP 1491502))]
|
(gdb) p total_key_length
|
$1 = 0
|
(gdb) p inner->max_length
|
Cannot access memory at address 0x8f8f8f8f8f8f8f97
|
|
|
It's poisoned memory by a free() in removing a redundant group by clause in subquery.
(gdb) p select_lex->first_inner_unit()->first_select()->join->fields_list
|
$27 = (List<Item> &) @0x2edb1310: {<base_list> = {<Sql_alloc> = {<No data fields>}, first = 0x2edb0fa0, last = 0x2edb0fa0, elements = 1}, <No data fields>}
|
(gdb) monitor get_vbits 0x2edb0fa0 10
|
00000000 00000000 0000
|
|
|
|
V
|
|
(gdb) monitor get_vbits 0x2edb0fa0 10
|
________ ________ ____
|
Address 0x2EDB0FA0 len 10 has 10 bytes unaddressable
|
The offending piece of code is in remove_redundant_subquery_clauses()
/*
|
Remove from the JOIN::all_fields list any reference to the elements
|
of the eliminated GROUP BY list unless it is 'in_field_list'.
|
This is needed in order not to confuse JOIN::make_aggr_tables_info()
|
when it constructs different structure for execution phase.
|
*/
|
List_iterator<Item> li(subq_select_lex->join->all_fields);
|
Item *item;
|
while ((item= li++))
|
{
|
if (item == *ord->item)
|
li.remove();
|
}
|
Will fix when I figure out how. 
|
|
Great going 
|
|
Hi Igor,
I was given this MDEV to look at by Sergei P. Looks like it's your code, I have no idea whether this is the right thing to do. Just guessing.
Cheers, Rex
|
|
and this still crashes...
PREPARE FOO from "UPDATE t SET c=1 WHERE c=2 ORDER BY (1 IN ((SELECT * FROM (SELECT * FROM t) AS v1 GROUP BY c WINDOW v2 AS (ORDER BY (SELECT * FROM t GROUP BY c WINDOW v3 AS (PARTITION BY c))))))";
EXECUTE FOO;
|
|
Found an additional testcase for use-after-poison in base_list_iterator::next to test with.
CREATE TABLE x (x TEXT);
|
SELECT (x=(SELECT x FROM x WHERE (x,x) NOT IN (SELECT''* x * 1,''FROM x WINDOW x AS (PARTITION BY x ORDER BY x ^ (SELECT 1 FROM x AS x WHERE x GROUP BY 1,x WINDOW x AS (PARTITION BY x ORDER BY (1))) ^ x RANGE BETWEEN 1 FOLLOWING AND 1 FOLLOWING))) * 1^ 1 IN (-1,0,1,0,''/ x=x + CASE x WHEN TRUE THEN 0 ELSE 1 END OR x=x OR x=x)),''/ 1 AS x FROM x WINDOW x AS (PARTITION BY x ORDER BY (SELECT 1 FROM x WHERE x GROUP BY (x=(SELECT x FROM x WHERE (x,x) NOT IN (SELECT 1)) * 1^ 1 IN (-1,0,1,0,''/ x=x + CASE WHEN TRUE THEN 0 ELSE 1 END OR x=x OR x=x)),x WINDOW x AS (PARTITION BY x ORDER BY (1))) RANGE BETWEEN 1 FOLLOWING AND 1 FOLLOWING);
|
|
|
Additional testcase with a very different stack, 10.4+ only, and a different ASAN use-after-poison in sql/sql_list.h
CREATE TABLE t (c INT);
|
SET SESSION optimizer_switch='materialization=OFF';
|
UPDATE t SET c=1 WHERE c='' ORDER BY 1=(1 IN ((SELECT * FROM (SELECT * FROM t) AS v3 NATURAL JOIN t AS v2 NATURAL JOIN t AS v4 GROUP BY c WINDOW v5 AS (ORDER BY (SELECT * FROM t GROUP BY c WINDOW v6 AS (PARTITION BY c))))));
|
Leads to:
|
10.11.2 70be59913c90e93fe5136d6f6df03c4254aa515d (Debug)
|
Core was generated by `/test/MD070123-mariadb-10.11.2-linux-x86_64-dbg/bin/mysqld --no-defaults --core'.
|
Program terminated with signal SIGSEGV, Segmentation fault.
|
#0 JOIN::eval_select_list_used_tables (this=0x14b870035148)
|
at /test/10.11_dbg/sql/sql_select.cc:13195
|
[Current thread is 1 (Thread 0x14b897147640 (LWP 2601256))]
|
(gdb) bt
|
#0 JOIN::eval_select_list_used_tables (this=0x14b870035148) at /test/10.11_dbg/sql/sql_select.cc:13195
|
#1 JOIN::optimize_inner (this=this@entry=0x14b870035148) at /test/10.11_dbg/sql/sql_select.cc:2112
|
#2 0x00005636942443aa in JOIN::optimize (this=this@entry=0x14b870035148) at /test/10.11_dbg/sql/sql_select.cc:1870
|
#3 0x000056369419066a in st_select_lex::optimize_unflattened_subqueries (this=0x14b8700057c8, const_only=const_only@entry=true) at /test/10.11_dbg/sql/sql_lex.cc:4907
|
#4 0x000056369436b32b in JOIN::optimize_constant_subqueries (this=this@entry=0x14b870034800) at /test/10.11_dbg/sql/opt_subselect.cc:5689
|
#5 0x0000563694242f3e in JOIN::optimize_inner (this=this@entry=0x14b870034800) at /test/10.11_dbg/sql/sql_select.cc:2193
|
#6 0x00005636942443aa in JOIN::optimize (this=this@entry=0x14b870034800) at /test/10.11_dbg/sql/sql_select.cc:1870
|
#7 0x000056369424449a in mysql_select (thd=thd@entry=0x14b870000d58, tables=tables@entry=0x14b870013390, fields=@0x14b897145d10: {<base_list> = {<Sql_alloc> = {<No data fields>}, first = 0x5636956a6f00 <end_of_list>, last = 0x14b897145d10, elements = 0}, <No data fields>}, conds=conds@entry=0x14b870013e18, og_num=1, order=0x14b87002adb0, group=0x0, having=0x0, proc_param=0x0, select_options=37383395344512, result=0x14b8700346f0, unit=0x14b870004f98, select_lex=0x14b8700057c8) at /test/10.11_dbg/sql/sql_select.cc:5066
|
#8 0x00005636942b980b in mysql_multi_update (thd=thd@entry=0x14b870000d58, table_list=0x14b870013390, fields=fields@entry=0x14b870005a68, values=values@entry=0x14b870005ea0, conds=0x14b870013e18, options=0, handle_duplicates=DUP_ERROR, ignore=false, unit=0x14b870004f98, select_lex=0x14b8700057c8, result=0x14b897145f00) at /test/10.11_dbg/sql/sql_update.cc:1980
|
#9 0x00005636941bcfa8 in mysql_execute_command (thd=thd@entry=0x14b870000d58, is_called_from_prepared_stmt=is_called_from_prepared_stmt@entry=false) at /test/10.11_dbg/sql/sql_parse.cc:4491
|
#10 0x00005636941c2c7a in mysql_parse (thd=thd@entry=0x14b870000d58, rawbuf=<optimized out>, length=<optimized out>, parser_state=parser_state@entry=0x14b8971462c0) at /test/10.11_dbg/sql/sql_parse.cc:8000
|
#11 0x00005636941c4e0e in dispatch_command (command=command@entry=COM_QUERY, thd=thd@entry=0x14b870000d58, packet=packet@entry=0x14b87000ae09 "UPDATE t SET c=1 WHERE c='' ORDER BY 1=(1 IN ((SELECT * FROM (SELECT * FROM t) AS v3 NATURAL JOIN t AS v2 NATURAL JOIN t AS v4 GROUP BY c WINDOW v5 AS (ORDER BY (SELECT * FROM t GROUP BY c WINDOW v6 A"..., packet_length=packet_length@entry=223, blocking=blocking@entry=true) at /test/10.11_dbg/sql/sql_class.h:243
|
#12 0x00005636941c6c67 in do_command (thd=0x14b870000d58, blocking=blocking@entry=true) at /test/10.11_dbg/sql/sql_parse.cc:1407
|
#13 0x0000563694310d30 in do_handle_one_connection (connect=<optimized out>, connect@entry=0x563697323838, put_in_cache=put_in_cache@entry=true) at /test/10.11_dbg/sql/sql_connect.cc:1416
|
#14 0x0000563694310f8f in handle_one_connection (arg=0x563697323838) at /test/10.11_dbg/sql/sql_connect.cc:1318
|
#15 0x000014b8c7a62b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
|
#16 0x000014b8c7af4a00 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
|
|
10.11.2 70be59913c90e93fe5136d6f6df03c4254aa515d (Optimized, UBASAN)
|
==2670205==ERROR: AddressSanitizer: use-after-poison on address 0x6290000888c0 at pc 0x5622357f717c bp 0x147d5641d9f0 sp 0x147d5641d9e0
|
READ of size 8 at 0x6290000888c0 thread T13
|
#0 0x5622357f717b in base_list_iterator::next_fast() /test/10.11_opt_san/sql/sql_list.h:443
|
#1 0x5622357f717b in List_iterator_fast<Item>::operator++(int) /test/10.11_opt_san/sql/sql_list.h:620
|
#2 0x5622357f717b in JOIN::eval_select_list_used_tables() /test/10.11_opt_san/sql/sql_select.cc:13193
|
#3 0x5622357f717b in JOIN::optimize_inner() /test/10.11_opt_san/sql/sql_select.cc:2112
|
#4 0x5622357fb2a0 in JOIN::optimize() /test/10.11_opt_san/sql/sql_select.cc:1870
|
#5 0x562235291342 in st_select_lex::optimize_unflattened_subqueries(bool) /test/10.11_opt_san/sql/sql_lex.cc:4907
|
#6 0x562235f675e7 in JOIN::optimize_constant_subqueries() /test/10.11_opt_san/sql/opt_subselect.cc:5689
|
#7 0x5622357f01a0 in JOIN::optimize_inner() /test/10.11_opt_san/sql/sql_select.cc:2193
|
#8 0x5622357fb2a0 in JOIN::optimize() /test/10.11_opt_san/sql/sql_select.cc:1870
|
#9 0x5622357fb936 in mysql_select(THD*, TABLE_LIST*, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) /test/10.11_opt_san/sql/sql_select.cc:5066
|
#10 0x562235b16be7 in mysql_multi_update(THD*, TABLE_LIST*, List<Item>*, List<Item>*, Item*, unsigned long long, enum_duplicates, bool, st_select_lex_unit*, st_select_lex*, multi_update**) /test/10.11_opt_san/sql/sql_update.cc:1980
|
#11 0x562235404878 in mysql_execute_command(THD*, bool) /test/10.11_opt_san/sql/sql_parse.cc:4491
|
#12 0x562235420d82 in mysql_parse(THD*, char*, unsigned int, Parser_state*) /test/10.11_opt_san/sql/sql_parse.cc:8000
|
#13 0x56223542e7e5 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) /test/10.11_opt_san/sql/sql_parse.cc:1894
|
#14 0x562235437f40 in do_command(THD*, bool) /test/10.11_opt_san/sql/sql_parse.cc:1407
|
#15 0x562235d1471c in do_handle_one_connection(CONNECT*, bool) /test/10.11_opt_san/sql/sql_connect.cc:1416
|
#16 0x562235d16d1c in handle_one_connection /test/10.11_opt_san/sql/sql_connect.cc:1318
|
#17 0x147d78315b42 in start_thread nptl/pthread_create.c:442
|
#18 0x147d783a79ff (/lib/x86_64-linux-gnu/libc.so.6+0x1269ff)
|
|
0x6290000888c0 is located 5824 bytes inside of 16400-byte region [0x629000087200,0x62900008b210)
|
allocated by thread T13 here:
|
#0 0x562234b4c887 in malloc (/test/UBASAN_MD070123-mariadb-10.11.2-linux-x86_64-opt/bin/mariadbd+0x7a20887)
|
#1 0x562238f71d14 in my_malloc /test/10.11_opt_san/mysys/my_malloc.c:90
|
#2 0x562238f4ce2b in root_alloc /test/10.11_opt_san/mysys/my_alloc.c:66
|
#3 0x562238f4ce2b in reset_root_defaults /test/10.11_opt_san/mysys/my_alloc.c:243
|
#4 0x56223508d24e in THD::init_for_queries() /test/10.11_opt_san/sql/sql_class.cc:1387
|
#5 0x562235d0f24e in prepare_new_connection_state(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1245
|
#6 0x562235d10b37 in thd_prepare_connection(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1339
|
#7 0x562235d10b37 in thd_prepare_connection(THD*) /test/10.11_opt_san/sql/sql_connect.cc:1328
|
#8 0x562235d137b7 in do_handle_one_connection(CONNECT*, bool) /test/10.11_opt_san/sql/sql_connect.cc:1406
|
#9 0x562235d16d1c in handle_one_connection /test/10.11_opt_san/sql/sql_connect.cc:1318
|
#10 0x147d78315b42 in start_thread nptl/pthread_create.c:442
|
|
Thread T13 created by T0 here:
|
#0 0x562234af06c5 in pthread_create (/test/UBASAN_MD070123-mariadb-10.11.2-linux-x86_64-opt/bin/mariadbd+0x79c46c5)
|
#1 0x562234ba4cfe in create_thread_to_handle_connection(CONNECT*) /test/10.11_opt_san/sql/mysqld.cc:6102
|
#2 0x562234bb712f in handle_accepted_socket(st_mysql_socket, st_mysql_socket) /test/10.11_opt_san/sql/mysqld.cc:6223
|
#3 0x562234bb80b7 in handle_connections_sockets() /test/10.11_opt_san/sql/mysqld.cc:6347
|
#4 0x562234bbb11d in mysqld_main(int, char**) /test/10.11_opt_san/sql/mysqld.cc:5997
|
#5 0x147d782aad8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
|
|
SUMMARY: AddressSanitizer: use-after-poison /test/10.11_opt_san/sql/sql_list.h:443 in base_list_iterator::next_fast()
|
Shadow bytes around the buggy address:
|
0x0c52800090c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c52800090d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c52800090e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f7
|
0x0c52800090f0: 00 00 f7 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
=>0x0c5280009110: 00 00 00 00 00 00 f7 f7[f7]f7 00 00 00 00 00 00
|
0x0c5280009120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0c5280009160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
Shadow byte legend (one shadow byte represents 8 application bytes):
|
Addressable: 00
|
Partially addressable: 01 02 03 04 05 06 07
|
Heap left redzone: fa
|
Freed heap region: fd
|
Stack left redzone: f1
|
Stack mid redzone: f2
|
Stack right redzone: f3
|
Stack after return: f5
|
Stack use after scope: f8
|
Global redzone: f9
|
Global init order: f6
|
Poisoned by user: f7
|
Container overflow: fc
|
Array cookie: ac
|
Intra object redzone: bb
|
ASan internal: fe
|
Left alloca redzone: ca
|
Right alloca redzone: cb
|
Shadow gap: cc
|
==2670205==ABORTING
|
Bug confirmed present in:
MariaDB: 10.4.28 (dbg), 10.5.19 (dbg), 10.6.12 (dbg), 10.7.8 (dbg), 10.8.7 (dbg), 10.9.5 (dbg), 10.10.3 (dbg), 10.11.2 (dbg)
Bug (or feature/syntax) confirmed not present in:
MariaDB: 10.3.38 (dbg), 10.3.38 (opt), 10.4.28 (opt), 10.5.19 (opt), 10.6.12 (opt), 10.7.8 (opt), 10.8.7 (opt), 10.9.5 (opt), 10.10.3 (opt), 10.11.2 (opt)
MySQL: 5.5.62 (dbg), 5.5.62 (opt), 5.6.51 (dbg), 5.6.51 (opt), 5.7.40 (dbg), 5.7.40 (opt), 8.0.31 (dbg), 8.0.31 (opt)
|
|
Hi Sergei. I returned to this after Roel added new test cases.
|
|
I keep running into this bug in various ways. New UniqueID with this testcase
CREATE TABLE t (c INT);
|
SET SESSION optimizer_trace=1;
|
UPDATE t SET c=1 WHERE c IN (SELECT * FROM t AS c NATURAL JOIN t WINDOW c AS (PARTITION BY 1 BETWEEN (SELECT 1 GROUP BY c WINDOW c AS (PARTITION BY c)) AND 1));
|
SIGSEGV|st_select_lex::print|opt_trace_print_expanded_query|JOIN::prepare|subselect_single_select_engine::prepare
|
Please verify this testcase after a fix found, as it may touch on another bug also (given the optimizer_trace setting requirement)
|
|
Debugging the original testcase...
The code in remove_redundant_subquery_clauses() removes elements from
subq_select_lex->join->all_fields:
|
/*
|
Remove from the JOIN::all_fields list any reference to the elements
|
of the eliminated GROUP BY list unless it is 'in_field_list'.
|
This is needed in order not to confuse JOIN::make_aggr_tables_info()
|
when it constructs different structure for execution phase.
|
*/
|
List_iterator<Item> li(subq_select_lex->join->all_fields);
|
Item *item;
|
while ((item= li++))
|
{
|
if (item == *ord->item)
|
li.remove();
|
}
|
While doing that, it corrupts subq_select_lex->item_list: immediately after the li.remove() call above one, one gets:
(gdb) p subq_select_lex->item_list
|
$88 = {<base_list> = {<Sql_alloc> = {<No data fields>}, first = 0x7fff78015598, last = 0x7fff78015598, elements = 1}, <No data fields>}
|
|
(gdb) p subq_select_lex->item_list->first[0]
|
$89 = {<Sql_alloc> = {<No data fields>}, next = 0x8f8f8f8f8f8f8f8f, info = 0x8f8f8f8f8f8f8f8f}
|
I'm not sure how this happens if these two are separate lists?
|
|
... they are not. item_list is the suffix of all_fields. Note the $PTR here:
(gdb) p subq_select_lex->join->all_fields
|
$98 = {<base_list> = {<Sql_alloc> = {<No data fields>}, first = 0x7fff6c02b610, last = $PTR, elements = 2}, <No data fields>}
|
(gdb) p subq_select_lex->item_list
|
$99 = {<base_list> = {<Sql_alloc> = {<No data fields>}, first = $PTR, last = $PTR, elements = 1}, <No data fields>}
|
(gdb) p subq_select_lex->join->all_fields.first[0]
|
$100 = {<Sql_alloc> = {<No data fields>}, next = $PTR, info = 0x7fff6c018988}
|
List contents:
(gdb) p subq_select_lex->join->all_fields.elem(0)
|
$102 = (Item_singlerow_subselect *) 0x7fff6c018988
|
(gdb) p subq_select_lex->join->all_fields.elem(1)
|
$103 = (Item_field *) 0x7fff6c02aa30
|
|
|
Take-away from the optimizer call: the observed "list sharing" is known and it was like that for a very long time.
|
|
PR updated after information from sanja details here
https://github.com/MariaDB/server/commit/da51a117e1271b2ac821571a45849ffa04d8be2a#diff-16fd8e507582e428d933bc7ee3984394eab544410785220b536ab964d4e9e084
|
|
Note: MDEV-29359 is fixed by the fix for this bug. MDEV-28515 (linked to MDEV-29359) is not fixed by fix for this bug.
|
|
Johnston, the patch technically works, but I see some flaws:
- why put the test in insert_select.test ? The failure is caused by the code which handles IN subqueries... I don't see how the INSERT part is necessary...
- There is a more efficient way to check if we've reached the part of the list which we should not touch...
- Some of the "discoveries" made while investigating this deserve code comments, I think...
|
|
Addressed all of the above in: https://github.com/MariaDB/server/commit/436abf9253d4f54e8a2c7400c33d65790b9e620c
sanja, could you please review?
|
|
sanja, one question that is still not clear to me: If the select list entry was NOT added by GROUP BY code, why does the ORDER structure have ord->in_field_list==false ? Is this correct? (It's hard for me to tell, because there's no exact definition of what in_field_list means).
And do we need the check for (!in_field_list) after this patch?
|
|
Let's execute the query:
UPDATE t SET c=1 WHERE c=2 ORDER BY (1 IN ((SELECT * FROM (SELECT * FROM t) AS v1 GROUP BY c WINDOW v2 AS (ORDER BY (SELECT * FROM t tt GROUP BY c WINDOW v3 AS (PARTITION BY c))))));
|
The cause of the problem can seen here:
(gdb) p thd->lex->all_selects_list
|
$122 = (SELECT_LEX *) 0x7fff90016990
|
(gdb) p dbug_print_select((SELECT_LEX *) 0x7fff90016990)
|
$123 = 0x555557581b40 <dbug_item_print_buf> "select `*` from test.t tt group by c"
|
(gdb) p ((SELECT_LEX *) 0x7fff90016990)->group_list
|
$124 = {<Sql_alloc> = {<No data fields>}, elements = 1, first = 0x7fff90017eb0, next = 0x7fff90017eb0}
|
(gdb) p ((SELECT_LEX *) 0x7fff90016990)->next_select_in_list()
|
$125 = (st_select_lex *) 0x7fff90014d38
|
(gdb) p dbug_print_select((st_select_lex *) 0x7fff90014d38)
|
$126 = 0x555557581b40 <dbug_item_print_buf> "select t.c AS c from test.t"
|
(gdb) p ((st_select_lex *) 0x7fff90014d38)->next_select_in_list()
|
$127 = (st_select_lex *) 0x7fff90014018
|
(gdb) p dbug_print_select((st_select_lex *) 0x7fff90014018)
|
$128 = 0x555557581b40 <dbug_item_print_buf> "select `*` from (select t.c AS c from test.t) v1 group by c"
|
(gdb) p ((st_select_lex *) 0x7fff90014018)->group_list
|
$129 = {<Sql_alloc> = {<No data fields>}, elements = 1, first = 0x7fff90017eb0, next = 0x7fff90017eb0}
|
Here we see that two different selects:
select `*` from (select t.c AS c from test.t) v1 group by c
|
select `*` from test.t tt group by c
|
share the same group_list.
We have this when starting to execute mysql_derived_prepare() for the derived table v1 called indirectly from Multiupdate_prelocking_strategy::handle_end()
|
|
Ok, this is a parser problem. Here's a fix:
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
|
index bdc8b54..548272f 100644
|
--- a/sql/sql_lex.h
|
+++ b/sql/sql_lex.h
|
@@ -976,6 +976,7 @@ class st_select_lex: public st_select_lex_node
|
*/
|
SQL_I_List<ORDER> group_list;
|
Group_list_ptrs *group_list_ptrs;
|
+ SQL_I_List<ORDER> save_group_list;
|
|
List<Item> item_list; /* list of fields & expressions */
|
List<Item> pre_fix; /* above list before fix_fields */
|
@@ -1040,6 +1041,7 @@ class st_select_lex: public st_select_lex_node
|
const char *type; /* type of select for EXPLAIN */
|
|
SQL_I_List<ORDER> order_list; /* ORDER clause */
|
+ SQL_I_List<ORDER> save_order_list;
|
SQL_I_List<ORDER> gorder_list;
|
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
|
|
@@ -3215,8 +3217,6 @@ struct LEX: public Query_tables_list
|
}
|
|
|
- SQL_I_List<ORDER> save_group_list;
|
- SQL_I_List<ORDER> save_order_list;
|
LEX_CSTRING *win_ref;
|
Window_frame *win_frame;
|
Window_frame_bound *frame_top_bound;
|
diff --git a/sql/sql_list.h b/sql/sql_list.h
|
index b112398..40848c2 100644
|
--- a/sql/sql_list.h
|
+++ b/sql/sql_list.h
|
@@ -53,7 +53,7 @@ class SQL_I_List :public Sql_alloc
|
{
|
elements= tmp.elements;
|
first= tmp.first;
|
- next= tmp.next;
|
--- a/sql/sql_list.h
|
+++ b/sql/sql_list.h
|
@@ -53,7 +53,7 @@ class SQL_I_List :public Sql_alloc
|
{
|
elements= tmp.elements;
|
first= tmp.first;
|
- next= tmp.next;
|
+ next= elements ? tmp.next : &first;
|
return *this;
|
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
|
index 5e4c41f..cfe8c91 100644
|
--- a/sql/sql_lex.cc
|
+++ b/sql/sql_lex.cc
|
@@ -755,8 +755,6 @@ void LEX::start(THD *thd_arg)
|
stmt_var_list.empty();
|
proc_list.elements=0;
|
|
- save_group_list.empty();
|
- save_order_list.empty();
|
win_ref= NULL;
|
win_frame= NULL;
|
frame_top_bound= NULL;
|
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
|
index 3102aa6..f360b24 100644
|
--- a/sql/sql_parse.cc
|
+++ b/sql/sql_parse.cc
|
@@ -8662,8 +8662,8 @@ TABLE_LIST *st_select_lex::convert_right_join()
|
void st_select_lex::prepare_add_window_spec(THD *thd)
|
{
|
LEX *lex= thd->lex;
|
- lex->save_group_list= group_list;
|
- lex->save_order_list= order_list;
|
+ save_group_list= group_list;
|
+ save_order_list= order_list;
|
lex->win_ref= NULL;
|
lex->win_frame= NULL;
|
lex->frame_top_bound= NULL;
|
@@ -8690,8 +8690,8 @@ bool st_select_lex::add_window_def(THD *thd,
|
win_part_list_ptr,
|
win_order_list_ptr,
|
win_frame);
|
- group_list= thd->lex->save_group_list;
|
- order_list= thd->lex->save_order_list;
|
+ group_list= save_group_list;
|
+ order_list= save_order_list;
|
if (parsing_place != SELECT_LIST)
|
{
|
fields_in_window_functions+= win_part_list_ptr->elements +
|
@@ -8717,8 +8717,8 @@ bool st_select_lex::add_window_spec(THD *thd,
|
win_part_list_ptr,
|
win_order_list_ptr,
|
win_frame);
|
- group_list= thd->lex->save_group_list;
|
- order_list= thd->lex->save_order_list;
|
+ group_list= save_group_list;
|
+ order_list= save_order_list;
|
if (parsing_place != SELECT_LIST)
|
{
|
fields_in_window_functions+= win_part_list_ptr->elements +
|
This fixes the problem.
|
|
Igor's patch passes all mtr tests, one interesting thing. Previously this
SELECT
|
id IN (SELECT id FROM t1
|
WINDOW w AS (ORDER BY
|
(SELECT 1 FROM t1 WHERE EXISTS
|
( SELECT id FROM t1 GROUP BY id
|
WINDOW w2 AS (ORDER BY id)
|
)))) FROM t1
|
emitted a warning
Column 'id' in group statement is ambiguous
With the patch, it's gone.
|