1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-24907: Empty the source list after merging an Item_equal

With save_merged false, Item_equal::merge_into_list() merges this
object's Item_equal instances into another, linking *this object's
items into the target.  However this allowed callers to free an
item via one list but later read it through the other; a case of
use-after-free.

If save_merged is false then delete the items from the source.
This commit is contained in:
Dave Gosselin
2026-10-01 15:08:57 -04:00
committed by Dave Gosselin
parent e79cd93f79
commit a11e9e7e9c
4 changed files with 85 additions and 0 deletions

View File

@@ -2754,6 +2754,30 @@ SELECT * FROM t1 WHERE (0,0) IN (SELECT MAX(c),MIN(c) FROM t1);
c
0
DROP TABLE t1;
#
# MDEV-24907: Empty the source list after merging an Item_equal
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0,0);
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (2),(0);
CREATE TABLE t3 (d INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES (1),(3);
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b NOT IN (SELECT d FROM t3)
) WHERE (t1.a, t3.d) IN (SELECT c, MAX(c) FROM t2) AND t1.a = t1.b;
a b c d
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b > 3
) WHERE t1.a IN (SELECT MAX(c) FROM t2 GROUP BY c) AND
t3.d IN (SELECT COUNT(c) FROM t2 GROUP BY c) AND
t1.a = t1.b;
a b c d
DROP TABLE t1, t2, t3;
# end of 10.11 tests
set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';

View File

@@ -2796,4 +2796,28 @@ SELECT * FROM t1 WHERE (0,0) IN (SELECT MAX(c),MIN(c) FROM t1);
c
0
DROP TABLE t1;
#
# MDEV-24907: Empty the source list after merging an Item_equal
#
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0,0);
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (2),(0);
CREATE TABLE t3 (d INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES (1),(3);
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b NOT IN (SELECT d FROM t3)
) WHERE (t1.a, t3.d) IN (SELECT c, MAX(c) FROM t2) AND t1.a = t1.b;
a b c d
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b > 3
) WHERE t1.a IN (SELECT MAX(c) FROM t2 GROUP BY c) AND
t3.d IN (SELECT COUNT(c) FROM t2 GROUP BY c) AND
t1.a = t1.b;
a b c d
DROP TABLE t1, t2, t3;
# end of 10.11 tests

View File

@@ -2472,4 +2472,31 @@ SELECT * FROM t1 WHERE (0,0) IN (SELECT MAX(c),MIN(c) FROM t1);
DROP TABLE t1;
--echo #
--echo # MDEV-24907: Empty the source list after merging an Item_equal
--echo #
CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (0,0);
CREATE TABLE t2 (c INT) ENGINE=MyISAM;
INSERT INTO t2 VALUES (2),(0);
CREATE TABLE t3 (d INT) ENGINE=MyISAM;
INSERT INTO t3 VALUES (1),(3);
# Result should be empty.
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b NOT IN (SELECT d FROM t3)
) WHERE (t1.a, t3.d) IN (SELECT c, MAX(c) FROM t2) AND t1.a = t1.b;
SELECT * FROM t1 LEFT JOIN (
t2 JOIN t3 ON (t3.d = t2.c)
) ON (
t1.b > 3
) WHERE t1.a IN (SELECT MAX(c) FROM t2 GROUP BY c) AND
t3.d IN (SELECT COUNT(c) FROM t2 GROUP BY c) AND
t1.a = t1.b;
DROP TABLE t1, t2, t3;
--echo # end of 10.11 tests

View File

@@ -7233,7 +7233,17 @@ void Item_equal::merge_into_list(THD *thd, List<Item_equal> *list,
if (!merge_into)
{
if (item->merge_with_check(thd, this, save_merged))
{
merge_into= item;
/*
If the caller doesn't set save_merged, then remove the items from the
source, which is 'this' object. That prevents an ASAN problem where
an item appearing in both lists has its memory deleted via one list
and then is later read via the other.
*/
if (!save_merged)
equal_items.empty();
}
}
else
{