Details
-
Task
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
5.6.5, 6.4.2
-
None
-
None
Description
REPLACE('a', 'pqrs', 'b') can provoke invalid length assertion when used with charset that is not multibyte and has MY_CS_BINSORT flag set. This is latin1_bin charset, for one example.
The code:
const string& str = fp[0]->data()->getStrVal(row, isNull); |
if (isNull) |
return ""; |
size_t strLen = str.length(); |
|
const string& fromstr = fp[1]->data()->getStrVal(row, isNull); |
if (isNull) |
return ""; |
if (fromstr.length() == 0) |
return str; |
size_t fromLen = fromstr.length(); |
|
const string& tostr = fp[2]->data()->getStrVal(row, isNull); |
if (isNull) |
return ""; |
size_t toLen = tostr.length(); |
|
bool binaryCmp = (cs->state & MY_CS_BINSORT) || !cs->use_mb(); |
string newstr;
|
size_t pos = 0; |
if (binaryCmp) |
{
|
// Count the number of fromstr in strend so we can reserve buffer space. |
int count = 0; |
do |
{
|
++count;
|
pos = str.find(fromstr, pos + fromLen);
|
} while (pos != string::npos); |
|
newstr.reserve(strLen + (count * ((int)toLen - (int)fromLen)) + 1); // <- the culprit. |
|
uint32_t i = 0;
|
pos = str.find(fromstr);
|
if (pos == string::npos) |
return str; |
// Move the stuff into newstr |
do |
{
|
if (pos > i) |
newstr = newstr + str.substr(i, pos - i);
|
|
newstr = newstr + tostr;
|
i = pos + fromLen;
|
pos = str.find(fromstr, i);
|
} while (pos != string::npos); |
|
newstr = newstr + str.substr(i, string::npos);
|
}
|
...
|
We count number of occurences starting with 1, even if there are no occurences of "fromstring" in the string "str" we are processing. Then we calculate signed integer difference between string to replace to "tostr" and string to replace "fromstring" and multiply it by count of occurences found plus 1.
For string to process 'a', string to replace 'pqrs' and string to replace to 'a', the difference will be negative -3, count will be 1 and string to process length is 1. The end result will be a value that is about 4G bytes long or even more.