diff --git a/mysql-test/main/func_str.result b/mysql-test/main/func_str.result index 8043985728e..5765af00e41 100644 --- a/mysql-test/main/func_str.result +++ b/mysql-test/main/func_str.result @@ -5696,4 +5696,34 @@ a b a b 1 1 1 1 2 3 NULL NULL drop table t1; +# +# MDEV-41496 OOB write with RPAD() crash and multi-byte charsets +# +SET @p=_latin1'x'; +SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL +WHERE (@p := CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; +LENGTH(RPAD(_latin1'a', 766, @p)) +766 +EXPLAIN EXTENDED SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL +WHERE (@p := CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select octet_length(rpad('a',766,convert(@`p` using ucs2))) AS `LENGTH(RPAD(_latin1'a', 766, @p))` where 1 +EXPLAIN EXTENDED SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL +WHERE (@p = CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select octet_length(rpad('a',766,@`p`)) AS `LENGTH(RPAD(_latin1'a', 766, @p))` where 1 +SET @p=_utf16'x'; +SELECT LENGTH(RPAD(_utf16'a', 766, @p)) FROM DUAL +WHERE (@p := CONCAT(_latin1'ab', _latin1 0xD800, REPEAT(_latin1'z',1000))) IS NOT NULL; +LENGTH(RPAD(_utf16'a', 766, @p)) +1532 +SET @p= _utf8mb3'b'; +SELECT HEX(CONCAT(_utf8mb3'a', @p)) FROM DUAL +WHERE (@p := _ucs2 0x00FF) IS NOT NULL; +HEX(CONCAT(_utf8mb3'a', @p)) +61C3BF # End of 10.11 tests diff --git a/mysql-test/main/func_str.test b/mysql-test/main/func_str.test index 2102cf271c7..470ace16229 100644 --- a/mysql-test/main/func_str.test +++ b/mysql-test/main/func_str.test @@ -2633,4 +2633,26 @@ insert t1 values (1,1),(2,3); select * from t1 left join t1 t2 on (t1.a=t2.b) where quote(t2.b)>''; drop table t1; +--echo # +--echo # MDEV-41496 OOB write with RPAD() crash and multi-byte charsets +--echo # + +SET @p=_latin1'x'; +SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL + WHERE (@p := CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; + +# charset convertor if @p is assigned to, no convertor otherwise +EXPLAIN EXTENDED SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL + WHERE (@p := CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; +EXPLAIN EXTENDED SELECT LENGTH(RPAD(_latin1'a', 766, @p)) FROM DUAL + WHERE (@p = CONVERT(UNHEX('0034002d') USING ucs2)) IS NOT NULL; + +SET @p=_utf16'x'; +SELECT LENGTH(RPAD(_utf16'a', 766, @p)) FROM DUAL + WHERE (@p := CONCAT(_latin1'ab', _latin1 0xD800, REPEAT(_latin1'z',1000))) IS NOT NULL; + +SET @p= _utf8mb3'b'; +SELECT HEX(CONCAT(_utf8mb3'a', @p)) FROM DUAL +WHERE (@p := _ucs2 0x00FF) IS NOT NULL; + --echo # End of 10.11 tests diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index cd4b708a96c..fa0c99a44ff 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5808,8 +5808,8 @@ CREATE TABLE t (f VARCHAR(8)) CHARACTER SET utf8; INSERT INTO t VALUES ('foo'),('bar'); EXECUTE IMMEDIATE 'SELECT GROUP_CONCAT(@x) FROM t GROUP BY @x := f'; GROUP_CONCAT(@x) -0 -0 +bar +foo DROP TABLE t; # # MDEV-15703: Crash in EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a INT DEFAULT ?)' USING DEFAULT diff --git a/sql/item_func.cc b/sql/item_func.cc index 09950722e14..20afff59eed 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4721,6 +4721,14 @@ bool Item_func_user_var::check_vcol_func_processor(void *arg) return mark_unsupported_function("@", name.str, arg, VCOL_NON_DETERMINISTIC); } +Item *Item_func_user_var::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) +{ + if (const_item()) + return Item::safe_charset_converter(thd, tocs); + /* always convert, ignore 'conv->safe' as we don't know the charset yet */ + return new (thd->mem_root) Item_func_conv_charset(thd, this, tocs, 0); +} + #define extra_size sizeof(double) user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name, diff --git a/sql/item_func.h b/sql/item_func.h index 1cbe08b6b68..51c1385cedc 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,7 +1,7 @@ #ifndef ITEM_FUNC_INCLUDED #define ITEM_FUNC_INCLUDED /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2021, MariaDB + Copyright (c) 2009, 2026, MariaDB plc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3552,6 +3552,7 @@ public: { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; };