MDEV-31764: ASAN use-after-poison in trace_engine_stats in ANALYZE JSON
Do not attempt to produce "r_engine_stats" on the temporary (=work) tables. These tables may be - re-created during the query execution - freed during the query execution (This is done e.g. in JOIN::cleanup(), before we produce ANALYZE FORMAT=JSON output). - (Also, make save_explain_data() functions not set handler_for_stats to point to handler objects that do not have handler->handler_stats set. If the storage engine is not collecting handler_stats, it will not have them when we're producing ANALYZE FORMAT=JSON output, either).
This commit is contained in:
parent
138717b16f
commit
691e964d23
@ -103,3 +103,70 @@ select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_
|
||||
PAGES_UPDATED_MORE_THAN_ZERO
|
||||
1
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-31764: ASAN use-after-poison in trace_engine_stats upon ANALYZE FORMAT=JSON
|
||||
#
|
||||
ANALYZE FORMAT=JSON SELECT count(*) FROM information_schema.GLOBAL_STATUS;
|
||||
# Another testcase without I_S:
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 SELECT seq FROM seq_1_to_100;
|
||||
CREATE TABLE t2 (s INT);
|
||||
INSERT INTO t2 SELECT seq FROM seq_1_to_10;
|
||||
# Must use SJ-Materialization to hit the issue with temp.table:
|
||||
ANALYZE FORMAT=JSON SELECT * FROM t1 WHERE a IN (SELECT s FROM t2);
|
||||
ANALYZE
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"r_loops": 1,
|
||||
"r_total_time_ms": "REPLACED",
|
||||
"const_condition": "1",
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 100,
|
||||
"r_rows": 100,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"r_engine_stats": REPLACED,
|
||||
"filtered": 100,
|
||||
"r_filtered": 100
|
||||
},
|
||||
"table": {
|
||||
"table_name": "<subquery2>",
|
||||
"access_type": "eq_ref",
|
||||
"possible_keys": ["distinct_key"],
|
||||
"key": "distinct_key",
|
||||
"key_length": "4",
|
||||
"used_key_parts": ["s"],
|
||||
"ref": ["func"],
|
||||
"r_loops": 100,
|
||||
"rows": 1,
|
||||
"r_rows": 0.1,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"filtered": 100,
|
||||
"r_filtered": 100,
|
||||
"materialized": {
|
||||
"unique": 1,
|
||||
"query_block": {
|
||||
"select_id": 2,
|
||||
"table": {
|
||||
"table_name": "t2",
|
||||
"access_type": "ALL",
|
||||
"r_loops": 1,
|
||||
"rows": 10,
|
||||
"r_rows": 10,
|
||||
"r_table_time_ms": "REPLACED",
|
||||
"r_other_time_ms": "REPLACED",
|
||||
"r_engine_stats": REPLACED,
|
||||
"filtered": 100,
|
||||
"r_filtered": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DROP TABLE t1, t2;
|
||||
|
@ -62,3 +62,23 @@ select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_
|
||||
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-31764: ASAN use-after-poison in trace_engine_stats upon ANALYZE FORMAT=JSON
|
||||
--echo #
|
||||
|
||||
--disable_result_log
|
||||
ANALYZE FORMAT=JSON SELECT count(*) FROM information_schema.GLOBAL_STATUS;
|
||||
--enable_result_log
|
||||
|
||||
--echo # Another testcase without I_S:
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 SELECT seq FROM seq_1_to_100;
|
||||
CREATE TABLE t2 (s INT);
|
||||
INSERT INTO t2 SELECT seq FROM seq_1_to_10;
|
||||
|
||||
--echo # Must use SJ-Materialization to hit the issue with temp.table:
|
||||
--source include/analyze-format.inc
|
||||
ANALYZE FORMAT=JSON SELECT * FROM t1 WHERE a IN (SELECT s FROM t2);
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
@ -124,9 +124,12 @@ bool Update_plan::save_explain_data_intern(THD *thd,
|
||||
if (is_analyze ||
|
||||
(thd->variables.log_slow_verbosity &
|
||||
LOG_SLOW_VERBOSITY_ENGINE))
|
||||
{
|
||||
table->file->set_time_tracker(&explain->table_tracker);
|
||||
|
||||
explain->handler_for_stats= table->file;
|
||||
if (table->file->handler_stats && table->s->tmp_table != INTERNAL_TMP_TABLE)
|
||||
explain->handler_for_stats= table->file;
|
||||
}
|
||||
|
||||
select_lex->set_explain_type(TRUE);
|
||||
explain->select_type= select_lex->type;
|
||||
|
@ -845,12 +845,18 @@ public:
|
||||
Gap_time_tracker extra_time_tracker;
|
||||
|
||||
/*
|
||||
Note: This pointer is only valid until notify_tables_are_closed() is
|
||||
called. After that, the tables may be freed or reused, together with their
|
||||
handler_stats objects.
|
||||
Handler object to get the handler_stats from.
|
||||
|
||||
Notes:
|
||||
This pointer is only valid until notify_tables_are_closed() is called.
|
||||
After that, the tables may be freed or reused, together with their
|
||||
handler_stats objects.
|
||||
notify_tables_are_closed() disables printing of FORMAT=JSON output.
|
||||
r_engine_stats is only printed in FORMAT=JSON output, so we're fine.
|
||||
|
||||
We do not store pointers to temporary (aka "work") tables here.
|
||||
Temporary tables may be freed (e.g. by JOIN::cleanup()) or re-created
|
||||
during query execution (when HEAP table is converted into Aria).
|
||||
*/
|
||||
handler *handler_for_stats;
|
||||
|
||||
|
@ -27755,12 +27755,16 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
|
||||
LOG_SLOW_VERBOSITY_ENGINE))
|
||||
{
|
||||
table->file->set_time_tracker(&eta->op_tracker);
|
||||
|
||||
/*
|
||||
Set handler_for_stats even if we are not running an ANALYZE command.
|
||||
There's no harm, and in case somebody runs a SHOW ANALYZE command we'll
|
||||
be able to print the engine statistics.
|
||||
*/
|
||||
eta->handler_for_stats= table->file;
|
||||
if (table->file->handler_stats &&
|
||||
table->s->tmp_table != INTERNAL_TMP_TABLE)
|
||||
eta->handler_for_stats= table->file;
|
||||
|
||||
if (likely(thd->lex->analyze_stmt))
|
||||
{
|
||||
eta->op_tracker.set_gap_tracker(&eta->extra_time_tracker);
|
||||
|
Loading…
x
Reference in New Issue
Block a user