diff options
author | Michael Widenius <monty@mariadb.org> | 2021-08-25 22:16:19 +0300 |
---|---|---|
committer | Michael Widenius <monty@mariadb.org> | 2021-08-26 07:07:46 +0300 |
commit | b378ddb3d3c3af75195d328018259369671bb029 (patch) | |
tree | ff8b637b1589eec9d22a0b01fbb160b823abc9ab /sql/sql_base.cc | |
parent | c9851d35adb1675ce204b2c77ac57da9023792ac (diff) | |
download | mariadb-git-b378ddb3d3c3af75195d328018259369671bb029.tar.gz |
MDEV 22785 Crash with prepared statements and NEXTVAL()
The problem was that a PREARE followed by a non prepared statement
using DEFAULT NEXT_VALUE() could change table->next_local to point to
a not persitent memory aria. The next EXECUTE would then try to use
the wrong pointer, which could cause a crash.
Fixed by reseting the pointer to it's old value when doing EXECUTE.
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2b06cf27d9b..f5eb0857d54 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4450,13 +4450,13 @@ bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, } -static bool internal_table_exists(TABLE_LIST *global_list, - const char *table_name) +static TABLE_LIST *internal_table_exists(TABLE_LIST *global_list, + const char *table_name) { do { if (global_list->table_name.str == table_name) - return 1; + return global_list; } while ((global_list= global_list->next_global)); return 0; } @@ -4471,13 +4471,23 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, do { + TABLE_LIST *tmp __attribute__((unused)); DBUG_PRINT("info", ("table name: %s", tables->table_name.str)); /* Skip table if already in the list. Can happen with prepared statements */ - if (tables->next_local && - internal_table_exists(global_table_list, tables->table_name.str)) + if ((tmp= internal_table_exists(global_table_list, + tables->table_name.str))) + { + /* + Use the original value for the next local, used by the + original prepared statement. We cannot trust the original + next_local value as it may have been changed by a previous + statement using the same table. + */ + tables->next_local= tmp; continue; + } TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); if (!tl) |