diff options
author | Alexander Barkov <bar@mariadb.com> | 2021-11-02 16:02:56 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2021-11-02 16:02:56 +0400 |
commit | 25191a419e98e03d9447753e1af06a3ff5821806 (patch) | |
tree | 6d697101b23a1b4b9e17efc98c370522c47675d6 | |
parent | d352bc5b6772f735a7e4bc540f578e0efc280e71 (diff) | |
download | mariadb-git-bb-10.4-MDEV-26953.tar.gz |
MDEV-26953 Assertion `!str || str != Ptr || !is_alloced()' failed in String::copy upon SELECT with sjisbb-10.4-MDEV-26953
Item::save_str_in_field() passes &Item::str_value as a parameter
to val_str().
Item_func::make_empty_result() also fills and returns str_value.
As a result, in the reported scenario in
Item_func::val_str_from_val_str_ascii()
both "str" and "res" pointed to Item::str_value,
which made the DBUG_ASSERT inside String::copy()
(preventing copying to itself) crash:
if ((null_value= str->copy(res->ptr(), res->length(),
&my_charset_latin1, collation.collation,
&errors)))
Fix:
- Adding a String* parameter to make_empty_result()
- Passing the val_str() parameter to make_empty_string().
-rw-r--r-- | mysql-test/main/ctype_sjis.result | 16 | ||||
-rw-r--r-- | mysql-test/main/ctype_sjis.test | 19 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 50 | ||||
-rw-r--r-- | sql/item_strfunc.h | 26 |
4 files changed, 73 insertions, 38 deletions
diff --git a/mysql-test/main/ctype_sjis.result b/mysql-test/main/ctype_sjis.result index fdb24fdc0e5..42f4f5141a8 100644 --- a/mysql-test/main/ctype_sjis.result +++ b/mysql-test/main/ctype_sjis.result @@ -19296,3 +19296,19 @@ SET STORAGE_ENGINE=Default; # # End of 10.2 tests # +# +# Start of 10.4 tests +# +# +# MDEV-26953 Assertion `!str || str != Ptr || !is_alloced()' failed in String::copy upon SELECT with sjis +# +SET NAMES sjis; +CREATE TABLE t (a VARCHAR(3)); +INSERT INTO t VALUES (''),(''); +SELECT GROUP_CONCAT(PASSWORD(a)) AS f FROM t; +f +, +DROP TABLE t; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/ctype_sjis.test b/mysql-test/main/ctype_sjis.test index 9a8ce414c14..00662fdf2a0 100644 --- a/mysql-test/main/ctype_sjis.test +++ b/mysql-test/main/ctype_sjis.test @@ -260,3 +260,22 @@ let $coll_pad='sjis_bin'; --echo # --echo # End of 10.2 tests --echo # + + +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-26953 Assertion `!str || str != Ptr || !is_alloced()' failed in String::copy upon SELECT with sjis +--echo # + +SET NAMES sjis; +CREATE TABLE t (a VARCHAR(3)); +INSERT INTO t VALUES (''),(''); +SELECT GROUP_CONCAT(PASSWORD(a)) AS f FROM t; +DROP TABLE t; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4e9d9df0990..a250a968418 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -739,7 +739,7 @@ String *Item_func_des_encrypt::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) - return make_empty_result(); + return make_empty_result(str); if (arg_count == 1) { /* Protect against someone doing FLUSH DES_KEY_FILE */ @@ -942,7 +942,7 @@ String *Item_func_concat_ws::val_str(String *str) } if (i == arg_count) - return make_empty_result(); + return make_empty_result(str); for (i++; i < arg_count ; i++) { @@ -1093,7 +1093,7 @@ String *Item_func_reverse::val_str(String *str) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return make_empty_result(); + return make_empty_result(str); if (str->alloc(res->length())) { null_value= 1; @@ -1644,7 +1644,7 @@ String *Item_func_left::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); if ((res->length() <= (ulonglong) length) || (res->length() <= (char_pos= res->charpos((int) length)))) return res; @@ -1688,7 +1688,7 @@ String *Item_func_right::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return make_empty_result(); /* purecov: inspected */ + return make_empty_result(str); /* purecov: inspected */ if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ @@ -1730,7 +1730,7 @@ String *Item_func_substr::val_str(String *str) /* Negative or zero length, will return empty string. */ if ((arg_count == 3) && (length <= 0) && (length == 0 || !args[2]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -1741,12 +1741,12 @@ String *Item_func_substr::val_str(String *str) /* Assumes that the maximum length of a String is < INT_MAX32. */ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) - return make_empty_result(); + return make_empty_result(str); start= ((start < 0) ? res->numchars() + start : start - 1); start= res->charpos((int) start); if ((start < 0) || ((uint) start + 1 > res->length())) - return make_empty_result(); + return make_empty_result(str); length= res->charpos((int) length, (uint32) start); tmp_length= res->length() - start; @@ -1816,7 +1816,7 @@ String *Item_func_substr_index::val_str(String *str) null_value=0; uint delimiter_length= delimiter->length(); if (!res->length() || !delimiter_length || !count) - return make_empty_result(); // Wrong parameters + return make_empty_result(str); // Wrong parameters res->set_charset(collation.collation); @@ -2226,7 +2226,7 @@ String *Item_func_password::val_str_ascii(String *str) switch (alg){ case NEW: if (args[0]->null_value || res->length() == 0) - return make_empty_result(); + return make_empty_result(str); my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); break; @@ -2234,7 +2234,7 @@ String *Item_func_password::val_str_ascii(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return make_empty_result(); + return make_empty_result(str); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); break; @@ -2279,7 +2279,7 @@ String *Item_func_encrypt::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return make_empty_result(); + return make_empty_result(str); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); @@ -2574,7 +2574,7 @@ String *Item_func_soundex::val_str(String *str) for ( ; ; ) /* Skip pre-space */ { if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0) - return make_empty_result(); /* EOL or invalid byte sequence */ + return make_empty_result(str); /* EOL or invalid byte sequence */ if (rc == 1 && cs->ctype) { @@ -2599,7 +2599,7 @@ String *Item_func_soundex::val_str(String *str) { /* Extra safety - should not really happen */ DBUG_ASSERT(false); - return make_empty_result(); + return make_empty_result(str); } to+= rc; break; @@ -2901,7 +2901,7 @@ String *Item_func_make_set::val_str(String *str) ulonglong bits; bool first_found=0; Item **ptr=args+1; - String *result= make_empty_result(); + String *result= make_empty_result(str); bits=args[0]->val_int(); if ((null_value=args[0]->null_value)) @@ -2925,7 +2925,7 @@ String *Item_func_make_set::val_str(String *str) else { if (tmp_str.copy(*res)) // Don't use 'str' - return make_empty_result(); + return make_empty_result(str); result= &tmp_str; } } @@ -2935,11 +2935,11 @@ String *Item_func_make_set::val_str(String *str) { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return make_empty_result(); + return make_empty_result(str); result= &tmp_str; } if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) - return make_empty_result(); + return make_empty_result(str); } } } @@ -3080,7 +3080,7 @@ String *Item_func_repeat::val_str(String *str) null_value= 0; if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Bounds check on count: If this is triggered, we will error. */ @@ -3145,7 +3145,7 @@ String *Item_func_space::val_str(String *str) null_value= 0; if (count <= 0 && (count == 0 || !args[0]->unsigned_flag)) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. Bounds check on count: If this is triggered, we will error. @@ -3311,7 +3311,7 @@ String *Item_func_rpad::val_str(String *str) null_value=0; if (count == 0) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -3403,7 +3403,7 @@ String *Item_func_lpad::val_str(String *str) null_value=0; if (count == 0) - return make_empty_result(); + return make_empty_result(str); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -3751,7 +3751,7 @@ String *Item_func_hex::val_str_ascii_from_val_real(String *str) dec= ~(longlong) 0; else dec= (ulonglong) (val + (val > 0 ? 0.5 : -0.5)); - return str->set_hex(dec) ? make_empty_result() : str; + return str->set_hex(dec) ? make_empty_result(str) : str; } @@ -3762,7 +3762,7 @@ String *Item_func_hex::val_str_ascii_from_val_str(String *str) DBUG_ASSERT(res != str); if ((null_value= (res == NULL))) return NULL; - return str->set_hex(res->ptr(), res->length()) ? make_empty_result() : str; + return str->set_hex(res->ptr(), res->length()) ? make_empty_result(str) : str; } @@ -3771,7 +3771,7 @@ String *Item_func_hex::val_str_ascii_from_val_int(String *str) ulonglong dec= (ulonglong) args[0]->val_int(); if ((null_value= args[0]->null_value)) return 0; - return str->set_hex(dec) ? make_empty_result() : str; + return str->set_hex(dec) ? make_empty_result(str) : str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 826a978805e..9995c7c644d 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -35,21 +35,21 @@ protected: character set. No memory is allocated. @retval A pointer to the str_value member. */ - virtual String *make_empty_result() + virtual String *make_empty_result(String *str) { /* Reset string length to an empty string. We don't use str_value.set() as we don't want to free and potentially have to reallocate the buffer for each call. */ - if (!str_value.is_alloced()) - str_value.set("", 0, collation.collation); /* Avoid null ptrs */ + if (!str->is_alloced()) + str->set("", 0, collation.collation); /* Avoid null ptrs */ else { - str_value.length(0); /* Reuse allocated area */ - str_value.set_charset(collation.collation); + str->length(0); /* Reuse allocated area */ + str->set_charset(collation.collation); } - return &str_value; + return str; } public: Item_str_func(THD *thd): Item_func(thd) { decimals=NOT_FIXED_DEC; } @@ -503,7 +503,7 @@ class Item_func_substr_oracle :public Item_func_substr protected: longlong get_position() { longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; } - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_substr_oracle(THD *thd, Item *a, Item *b): @@ -544,7 +544,7 @@ protected: String *trimmed_value(String *res, uint32 offset, uint32 length) { if (length == 0) - return make_empty_result(); + return make_empty_result(&tmp_value); tmp_value.set(*res, offset, length); /* @@ -577,7 +577,7 @@ public: class Item_func_trim_oracle :public Item_func_trim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -616,7 +616,7 @@ public: class Item_func_ltrim_oracle :public Item_func_ltrim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -651,7 +651,7 @@ public: class Item_func_rtrim_oracle :public Item_func_rtrim { protected: - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } const char *func_name_ext() const { return "_oracle"; } public: @@ -1146,7 +1146,7 @@ public: class Item_func_rpad_oracle :public Item_func_rpad { - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): @@ -1181,7 +1181,7 @@ public: class Item_func_lpad_oracle :public Item_func_lpad { - String *make_empty_result() + String *make_empty_result(String *str) { null_value= 1; return NULL; } public: Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): |