Commit 3d69213e authored by Alexander Barkov's avatar Alexander Barkov

MDEV-26953 Assertion `!str || str != Ptr || !is_alloced()' failed in...

MDEV-26953 Assertion `!str || str != Ptr || !is_alloced()' failed in String::copy upon SELECT with sjis

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().
parent 47756774
...@@ -19296,3 +19296,19 @@ SET STORAGE_ENGINE=Default; ...@@ -19296,3 +19296,19 @@ SET STORAGE_ENGINE=Default;
# #
# End of 10.2 tests # 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
#
...@@ -260,3 +260,22 @@ let $coll_pad='sjis_bin'; ...@@ -260,3 +260,22 @@ let $coll_pad='sjis_bin';
--echo # --echo #
--echo # End of 10.2 tests --echo # End of 10.2 tests
--echo # --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 #
...@@ -739,7 +739,7 @@ String *Item_func_des_encrypt::val_str(String *str) ...@@ -739,7 +739,7 @@ String *Item_func_des_encrypt::val_str(String *str)
if ((null_value= args[0]->null_value)) if ((null_value= args[0]->null_value))
return 0; // ENCRYPT(NULL) == NULL return 0; // ENCRYPT(NULL) == NULL
if ((res_length=res->length()) == 0) if ((res_length=res->length()) == 0)
return make_empty_result(); return make_empty_result(str);
if (arg_count == 1) if (arg_count == 1)
{ {
/* Protect against someone doing FLUSH DES_KEY_FILE */ /* Protect against someone doing FLUSH DES_KEY_FILE */
...@@ -942,7 +942,7 @@ String *Item_func_concat_ws::val_str(String *str) ...@@ -942,7 +942,7 @@ String *Item_func_concat_ws::val_str(String *str)
} }
if (i == arg_count) if (i == arg_count)
return make_empty_result(); return make_empty_result(str);
for (i++; i < arg_count ; i++) for (i++; i < arg_count ; i++)
{ {
...@@ -1093,7 +1093,7 @@ String *Item_func_reverse::val_str(String *str) ...@@ -1093,7 +1093,7 @@ String *Item_func_reverse::val_str(String *str)
return 0; return 0;
/* An empty string is a special case as the string pointer may be null */ /* An empty string is a special case as the string pointer may be null */
if (!res->length()) if (!res->length())
return make_empty_result(); return make_empty_result(str);
if (str->alloc(res->length())) if (str->alloc(res->length()))
{ {
null_value= 1; null_value= 1;
...@@ -1644,7 +1644,7 @@ String *Item_func_left::val_str(String *str) ...@@ -1644,7 +1644,7 @@ String *Item_func_left::val_str(String *str)
/* if "unsigned_flag" is set, we have a *huge* positive number. */ /* if "unsigned_flag" is set, we have a *huge* positive number. */
if ((length <= 0) && (!args[1]->unsigned_flag)) if ((length <= 0) && (!args[1]->unsigned_flag))
return make_empty_result(); return make_empty_result(str);
if ((res->length() <= (ulonglong) length) || if ((res->length() <= (ulonglong) length) ||
(res->length() <= (char_pos= res->charpos((int) length)))) (res->length() <= (char_pos= res->charpos((int) length))))
return res; return res;
...@@ -1688,7 +1688,7 @@ String *Item_func_right::val_str(String *str) ...@@ -1688,7 +1688,7 @@ String *Item_func_right::val_str(String *str)
/* if "unsigned_flag" is set, we have a *huge* positive number. */ /* if "unsigned_flag" is set, we have a *huge* positive number. */
if ((length <= 0) && (!args[1]->unsigned_flag)) 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) if (res->length() <= (ulonglong) length)
return res; /* purecov: inspected */ return res; /* purecov: inspected */
...@@ -1730,7 +1730,7 @@ String *Item_func_substr::val_str(String *str) ...@@ -1730,7 +1730,7 @@ String *Item_func_substr::val_str(String *str)
/* Negative or zero length, will return empty string. */ /* Negative or zero length, will return empty string. */
if ((arg_count == 3) && (length <= 0) && if ((arg_count == 3) && (length <= 0) &&
(length == 0 || !args[2]->unsigned_flag)) (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. */ /* 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. */ /* 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) ...@@ -1741,12 +1741,12 @@ String *Item_func_substr::val_str(String *str)
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* Assumes that the maximum length of a String is < INT_MAX32. */
if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) ||
(args[1]->unsigned_flag && ((ulonglong) 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= ((start < 0) ? res->numchars() + start : start - 1);
start= res->charpos((int) start); start= res->charpos((int) start);
if ((start < 0) || ((uint) start + 1 > res->length())) if ((start < 0) || ((uint) start + 1 > res->length()))
return make_empty_result(); return make_empty_result(str);
length= res->charpos((int) length, (uint32) start); length= res->charpos((int) length, (uint32) start);
tmp_length= res->length() - start; tmp_length= res->length() - start;
...@@ -1816,7 +1816,7 @@ String *Item_func_substr_index::val_str(String *str) ...@@ -1816,7 +1816,7 @@ String *Item_func_substr_index::val_str(String *str)
null_value=0; null_value=0;
uint delimiter_length= delimiter->length(); uint delimiter_length= delimiter->length();
if (!res->length() || !delimiter_length || !count) if (!res->length() || !delimiter_length || !count)
return make_empty_result(); // Wrong parameters return make_empty_result(str); // Wrong parameters
res->set_charset(collation.collation); res->set_charset(collation.collation);
...@@ -2226,7 +2226,7 @@ String *Item_func_password::val_str_ascii(String *str) ...@@ -2226,7 +2226,7 @@ String *Item_func_password::val_str_ascii(String *str)
switch (alg){ switch (alg){
case NEW: case NEW:
if (args[0]->null_value || res->length() == 0) 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()); my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
break; break;
...@@ -2234,7 +2234,7 @@ String *Item_func_password::val_str_ascii(String *str) ...@@ -2234,7 +2234,7 @@ String *Item_func_password::val_str_ascii(String *str)
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 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()); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
break; break;
...@@ -2279,7 +2279,7 @@ String *Item_func_encrypt::val_str(String *str) ...@@ -2279,7 +2279,7 @@ String *Item_func_encrypt::val_str(String *str)
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return make_empty_result(); return make_empty_result(str);
if (arg_count == 1) if (arg_count == 1)
{ // generate random salt { // generate random salt
time_t timestamp=current_thd->query_start(); time_t timestamp=current_thd->query_start();
...@@ -2574,7 +2574,7 @@ String *Item_func_soundex::val_str(String *str) ...@@ -2574,7 +2574,7 @@ String *Item_func_soundex::val_str(String *str)
for ( ; ; ) /* Skip pre-space */ for ( ; ; ) /* Skip pre-space */
{ {
if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0) 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) if (rc == 1 && cs->ctype)
{ {
...@@ -2599,7 +2599,7 @@ String *Item_func_soundex::val_str(String *str) ...@@ -2599,7 +2599,7 @@ String *Item_func_soundex::val_str(String *str)
{ {
/* Extra safety - should not really happen */ /* Extra safety - should not really happen */
DBUG_ASSERT(false); DBUG_ASSERT(false);
return make_empty_result(); return make_empty_result(str);
} }
to+= rc; to+= rc;
break; break;
...@@ -2901,7 +2901,7 @@ String *Item_func_make_set::val_str(String *str) ...@@ -2901,7 +2901,7 @@ String *Item_func_make_set::val_str(String *str)
ulonglong bits; ulonglong bits;
bool first_found=0; bool first_found=0;
Item **ptr=args+1; Item **ptr=args+1;
String *result= make_empty_result(); String *result= make_empty_result(str);
bits=args[0]->val_int(); bits=args[0]->val_int();
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
...@@ -2925,7 +2925,7 @@ String *Item_func_make_set::val_str(String *str) ...@@ -2925,7 +2925,7 @@ String *Item_func_make_set::val_str(String *str)
else else
{ {
if (tmp_str.copy(*res)) // Don't use 'str' if (tmp_str.copy(*res)) // Don't use 'str'
return make_empty_result(); return make_empty_result(str);
result= &tmp_str; result= &tmp_str;
} }
} }
...@@ -2935,11 +2935,11 @@ String *Item_func_make_set::val_str(String *str) ...@@ -2935,11 +2935,11 @@ String *Item_func_make_set::val_str(String *str)
{ // Copy data to tmp_str { // Copy data to tmp_str
if (tmp_str.alloc(result->length()+res->length()+1) || if (tmp_str.alloc(result->length()+res->length()+1) ||
tmp_str.copy(*result)) tmp_str.copy(*result))
return make_empty_result(); return make_empty_result(str);
result= &tmp_str; result= &tmp_str;
} }
if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) 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) ...@@ -3080,7 +3080,7 @@ String *Item_func_repeat::val_str(String *str)
null_value= 0; null_value= 0;
if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) 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. */ /* Assumes that the maximum length of a String is < INT_MAX32. */
/* Bounds check on count: If this is triggered, we will error. */ /* Bounds check on count: If this is triggered, we will error. */
...@@ -3145,7 +3145,7 @@ String *Item_func_space::val_str(String *str) ...@@ -3145,7 +3145,7 @@ String *Item_func_space::val_str(String *str)
null_value= 0; null_value= 0;
if (count <= 0 && (count == 0 || !args[0]->unsigned_flag)) 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. Assumes that the maximum length of a String is < INT_MAX32.
Bounds check on count: If this is triggered, we will error. Bounds check on count: If this is triggered, we will error.
...@@ -3311,7 +3311,7 @@ String *Item_func_rpad::val_str(String *str) ...@@ -3311,7 +3311,7 @@ String *Item_func_rpad::val_str(String *str)
null_value=0; null_value=0;
if (count == 0) if (count == 0)
return make_empty_result(); return make_empty_result(str);
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* 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. */ /* 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) ...@@ -3403,7 +3403,7 @@ String *Item_func_lpad::val_str(String *str)
null_value=0; null_value=0;
if (count == 0) if (count == 0)
return make_empty_result(); return make_empty_result(str);
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* 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. */ /* 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) ...@@ -3751,7 +3751,7 @@ String *Item_func_hex::val_str_ascii_from_val_real(String *str)
dec= ~(longlong) 0; dec= ~(longlong) 0;
else else
dec= (ulonglong) (val + (val > 0 ? 0.5 : -0.5)); 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) ...@@ -3762,7 +3762,7 @@ String *Item_func_hex::val_str_ascii_from_val_str(String *str)
DBUG_ASSERT(res != str); DBUG_ASSERT(res != str);
if ((null_value= (res == NULL))) if ((null_value= (res == NULL)))
return 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) ...@@ -3771,7 +3771,7 @@ String *Item_func_hex::val_str_ascii_from_val_int(String *str)
ulonglong dec= (ulonglong) args[0]->val_int(); ulonglong dec= (ulonglong) args[0]->val_int();
if ((null_value= args[0]->null_value)) if ((null_value= args[0]->null_value))
return 0; return 0;
return str->set_hex(dec) ? make_empty_result() : str; return str->set_hex(dec) ? make_empty_result(str) : str;
} }
......
...@@ -35,21 +35,21 @@ class Item_str_func :public Item_func ...@@ -35,21 +35,21 @@ class Item_str_func :public Item_func
character set. No memory is allocated. character set. No memory is allocated.
@retval A pointer to the str_value member. @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 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 we don't want to free and potentially have to reallocate the buffer
for each call. for each call.
*/ */
if (!str_value.is_alloced()) if (!str->is_alloced())
str_value.set("", 0, collation.collation); /* Avoid null ptrs */ str->set("", 0, collation.collation); /* Avoid null ptrs */
else else
{ {
str_value.length(0); /* Reuse allocated area */ str->length(0); /* Reuse allocated area */
str_value.set_charset(collation.collation); str->set_charset(collation.collation);
} }
return &str_value; return str;
} }
public: public:
Item_str_func(THD *thd): Item_func(thd) { decimals=NOT_FIXED_DEC; } 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 ...@@ -503,7 +503,7 @@ class Item_func_substr_oracle :public Item_func_substr
protected: protected:
longlong get_position() longlong get_position()
{ longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; } { 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; } { null_value= 1; return NULL; }
public: public:
Item_func_substr_oracle(THD *thd, Item *a, Item *b): Item_func_substr_oracle(THD *thd, Item *a, Item *b):
...@@ -544,7 +544,7 @@ class Item_func_trim :public Item_str_func ...@@ -544,7 +544,7 @@ class Item_func_trim :public Item_str_func
String *trimmed_value(String *res, uint32 offset, uint32 length) String *trimmed_value(String *res, uint32 offset, uint32 length)
{ {
if (length == 0) if (length == 0)
return make_empty_result(); return make_empty_result(&tmp_value);
tmp_value.set(*res, offset, length); tmp_value.set(*res, offset, length);
/* /*
...@@ -577,7 +577,7 @@ class Item_func_trim :public Item_str_func ...@@ -577,7 +577,7 @@ class Item_func_trim :public Item_str_func
class Item_func_trim_oracle :public Item_func_trim class Item_func_trim_oracle :public Item_func_trim
{ {
protected: protected:
String *make_empty_result() String *make_empty_result(String *str)
{ null_value= 1; return NULL; } { null_value= 1; return NULL; }
const char *func_name_ext() const { return "_oracle"; } const char *func_name_ext() const { return "_oracle"; }
public: public:
...@@ -616,7 +616,7 @@ class Item_func_ltrim :public Item_func_trim ...@@ -616,7 +616,7 @@ class Item_func_ltrim :public Item_func_trim
class Item_func_ltrim_oracle :public Item_func_ltrim class Item_func_ltrim_oracle :public Item_func_ltrim
{ {
protected: protected:
String *make_empty_result() String *make_empty_result(String *str)
{ null_value= 1; return NULL; } { null_value= 1; return NULL; }
const char *func_name_ext() const { return "_oracle"; } const char *func_name_ext() const { return "_oracle"; }
public: public:
...@@ -651,7 +651,7 @@ class Item_func_rtrim :public Item_func_trim ...@@ -651,7 +651,7 @@ class Item_func_rtrim :public Item_func_trim
class Item_func_rtrim_oracle :public Item_func_rtrim class Item_func_rtrim_oracle :public Item_func_rtrim
{ {
protected: protected:
String *make_empty_result() String *make_empty_result(String *str)
{ null_value= 1; return NULL; } { null_value= 1; return NULL; }
const char *func_name_ext() const { return "_oracle"; } const char *func_name_ext() const { return "_oracle"; }
public: public:
...@@ -1146,7 +1146,7 @@ class Item_func_rpad :public Item_func_pad ...@@ -1146,7 +1146,7 @@ class Item_func_rpad :public Item_func_pad
class Item_func_rpad_oracle :public Item_func_rpad class Item_func_rpad_oracle :public Item_func_rpad
{ {
String *make_empty_result() String *make_empty_result(String *str)
{ null_value= 1; return NULL; } { null_value= 1; return NULL; }
public: public:
Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3):
...@@ -1181,7 +1181,7 @@ class Item_func_lpad :public Item_func_pad ...@@ -1181,7 +1181,7 @@ class Item_func_lpad :public Item_func_pad
class Item_func_lpad_oracle :public Item_func_lpad class Item_func_lpad_oracle :public Item_func_lpad
{ {
String *make_empty_result() String *make_empty_result(String *str)
{ null_value= 1; return NULL; } { null_value= 1; return NULL; }
public: public:
Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment