Commit eea15803 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-28268: Server crashes in Expression_cache_tracker::fetch_current_stats

Expression_cache_tmptable object uses an Expression_cache_tracker object
to report the statistics.

In the common scenario, Expression_cache_tmptable destructor sets
tracker->cache=NULL. The tracker object survives after the expression
cache is deleted and one may call cache_tracker->fetch_current_stats()
for it with no harm.

However a degenerate cache with no parameters does not set
tracker->cache=NULL in Expression_cache_tmptable destructor which
results in an attempt to use freed data in the
cache_tracker->fetch_current_stats() call.

Fixed by setting tracker->cache to NULL and wrapping the assignment into
a function.
parent c711abd1
......@@ -2841,4 +2841,79 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY tn eq_ref PRIMARY PRIMARY 32 test.tms.key1 1 Using where
set optimizer_switch=@tmp_os;
drop table t1, t10, t11;
#
# MDEV-28268: Server crashes in Expression_cache_tracker::fetch_current_stats
#
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,2),(3,4);
ANALYZE FORMAT=JSON
SELECT DISTINCT
(SELECT MIN(a) FROM t1 WHERE b <= ANY (SELECT a FROM t1)) AS f
FROM t1;
ANALYZE
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"duplicate_removal": {
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100
},
"subqueries": [
{
"expression_cache": {
"state": "disabled",
"r_loops": 0,
"query_block": {
"select_id": 2,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 50,
"attached_condition": "<nop>(<in_optimizer>(t1.b,(subquery#3) >= 4))"
},
"subqueries": [
{
"query_block": {
"select_id": 3,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100
}
}
}
]
}
}
}
]
}
}
}
}
DROP TABLE t1;
# End of 10.2 tests
......@@ -2351,4 +2351,19 @@ set optimizer_switch=@tmp_os;
drop table t1, t10, t11;
--echo #
--echo # MDEV-28268: Server crashes in Expression_cache_tracker::fetch_current_stats
--echo #
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,2),(3,4);
--source include/analyze-format.inc
ANALYZE FORMAT=JSON
SELECT DISTINCT
(SELECT MIN(a) FROM t1 WHERE b <= ANY (SELECT a FROM t1)) AS f
FROM t1;
# Cleanup
DROP TABLE t1;
--echo # End of 10.2 tests
......@@ -63,7 +63,7 @@ void Expression_cache_tmptable::disable_cache()
cache_table= NULL;
update_tracker();
if (tracker)
tracker->cache= NULL;
tracker->detach_from_cache();
}
......@@ -188,6 +188,8 @@ Expression_cache_tmptable::~Expression_cache_tmptable()
else
{
update_tracker();
if (tracker)
tracker->detach_from_cache();
tracker= NULL;
}
}
......
......@@ -83,7 +83,11 @@ class Expression_cache_tracker :public Sql_alloc
cache(c), hit(0), miss(0), state(UNINITED)
{}
private:
// This can be NULL if the cache is already deleted
Expression_cache *cache;
public:
ulong hit, miss;
enum expr_cache_state state;
......@@ -91,6 +95,7 @@ class Expression_cache_tracker :public Sql_alloc
void set(ulong h, ulong m, enum expr_cache_state s)
{hit= h; miss= m; state= s;}
void detach_from_cache() { cache= NULL; }
void fetch_current_stats()
{
if (cache)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment