diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index d37c728d6fb..651f0b235d5 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6836,6 +6836,16 @@ drop procedure p1; drop function f1; drop view v1; drop table t1; +drop procedure if exists `p2` $ +create procedure `p2`(in `a` text charset utf8) +begin +declare `pos` int default 1; +declare `str` text charset utf8; +set `str` := `a`; +select substr(`str`, `pos`+ 1 ) into `str`; +end $ +call `p2`('s s s s s s'); +drop procedure `p2`; # ------------------------------------------------------------------ # -- End of 5.0 tests # ------------------------------------------------------------------ diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 8477211f524..c1e8d4b6f6c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8023,6 +8023,24 @@ drop function f1; drop view v1; drop table t1; +# +# Bug#38469 invalid memory read and/or crash with utf8 text field, stored procedure, uservar +# +delimiter $; +--disable_warnings +drop procedure if exists `p2` $ +--enable_warnings +create procedure `p2`(in `a` text charset utf8) +begin + declare `pos` int default 1; + declare `str` text charset utf8; + set `str` := `a`; + select substr(`str`, `pos`+ 1 ) into `str`; +end $ +delimiter ;$ +call `p2`('s s s s s s'); +drop procedure `p2`; + --echo # ------------------------------------------------------------------ --echo # -- End of 5.0 tests --echo # ------------------------------------------------------------------ diff --git a/sql/field.cc b/sql/field.cc index b03cc140ade..16bf0fdb070 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7699,8 +7699,18 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) return 0; } - if (from == value.ptr()) + /* + If the 'from' address is in the range of the temporary 'value'- + object we need to copy the content to a different location or it will be + invalidated when the 'value'-object is reallocated to make room for + the new character set. + */ + if (from >= value.ptr() && from <= value.ptr()+value.length()) { + /* + If content of the 'from'-address is cached in the 'value'-object + it is possible that the content needs a character conversion. + */ uint32 dummy_offset; if (!String::needs_conversion(length, cs, field_charset, &dummy_offset)) { diff --git a/sql/field.h b/sql/field.h index 0d0d7fba116..aa69fea6bdd 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1597,8 +1597,16 @@ private: class Field_blob :public Field_longstr { protected: + /** + The number of bytes used to represent the length of the blob. + */ uint packlength; - String value; // For temporaries + + /** + The 'value'-object is a cache fronting the storage engine. + */ + String value; + public: Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg,