Valgrind exposed a problem with the join_cache for hash joins:
=25636== Conditional jump or move depends on uninitialised value(s)
==25636== at 0xA8FF4E: JOIN_CACHE_HASHED::init_hash_table() (sql_join_cache.cc:2901)
==25636== by 0xA8FCEA: JOIN_CACHE_HASHED::init(bool) (sql_join_cache.cc:2841)
==25636== by 0xA91381: JOIN_CACHE_BNLH::init(bool) (sql_join_cache.cc:3940)
==25636== by 0x8FD85A: JOIN::init_join_caches() (sql_select.cc:1878)
==25636== by 0x902058: JOIN::optimize_stage2() (sql_select.cc:3111)
==25636== by 0x8FF7F0: JOIN::optimize_inner() (sql_select.cc:2394)
==25636== by 0x8FCF7D: JOIN::optimize() (sql_select.cc:1711)
The reason for this was that avg_record_length has a random value if one used
SET optimizer_switch='optimize_join_buffer_size=off';
This causes either 'random size' memory to be allocated (up to join_buffer_size) which can
increase memory usage or if avg_record_length is less than the row size, memory overwrites in thd->mem_root, which is bad.
Fixed by setting avg_record_length in JOIN_CACHE_HASHED::init() before it's used.
Attachments
Issue Links
relates to
MDEV-34084main.join_cache_notasan 'innodb' fails by passing instead of failing on ER_OUTOFMEMORY on armhf and hppa
Open
MDEV-31348Assertion `last_key_entry >= end_pos' failed in virtual bool JOIN_CACHE_HASHED::put_record()
mysqltest: At line 30: query 'SELECT t1.i,t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i' succeeded - should have failed with error ER_OUTOFMEMORY (1037)...
The result from queries just before the failure was:
#
# MDEV-28217 Incorrect Join Execution When Controlling Join Buffer Size
#
CREATE TABLE t1 (i int PRIMARY KEY)engine=innodb;
INSERT INTO t1 VALUES (1332945389);
CREATE TABLE t2 (i int PRIMARY KEY)engine=innodb;
INSERT INTO t2 VALUES (1180244875), (1951338178);
SET SESSION join_buffer_size= X;
Warnings:
Warning X Truncated incorrect join_buffer_size value: 'X'
SET SESSION join_cache_level = 4;
SET optimizer_switch='optimize_join_buffer_size=on';
SELECT t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i;
i
SET optimizer_switch='optimize_join_buffer_size=off';
SELECT t1.i,t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i;
Otto Kekäläinen
added a comment - I saw a variation of this in https://buildd.debian.org/status/fetch.php?pkg=mariadb&arch=hppa&ver=1%3A10.11.5-2&stamp=1696821455&raw=0 (hppa build of Debian 1:10.11.5-2):
main.join_cache_notasan 'innodb' w1 [ fail ]
Test ended at 2023-10-09 03:16:39
CURRENT_TEST: main.join_cache_notasan
mysqltest: At line 30: query 'SELECT t1.i,t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i' succeeded - should have failed with error ER_OUTOFMEMORY (1037)...
The result from queries just before the failure was:
#
# MDEV-28217 Incorrect Join Execution When Controlling Join Buffer Size
#
CREATE TABLE t1 (i int PRIMARY KEY)engine=innodb;
INSERT INTO t1 VALUES (1332945389);
CREATE TABLE t2 (i int PRIMARY KEY)engine=innodb;
INSERT INTO t2 VALUES (1180244875), (1951338178);
SET SESSION join_buffer_size= X;
Warnings:
Warning X Truncated incorrect join_buffer_size value: 'X'
SET SESSION join_cache_level = 4;
SET optimizer_switch='optimize_join_buffer_size=on';
SELECT t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i;
i
SET optimizer_switch='optimize_join_buffer_size=off';
SELECT t1.i,t2.i FROM t2 LEFT JOIN t1 ON t1.i = t2.i WHERE t1.i;
wrong assignment