Skip to content

Commit 889a66a

Browse files
committed
BUG#36297142 - mysqld crash at vector::get_dot for ASAN
Problem ======= - At udf_handler::get_and_convert_string, we get a String* result pointer, which might be the address of Item::str_value. We then call c_ptr_safe() on this, so the buffer of Item::str_value gets reallocated. - Queries which have UDFs consuming the same argument more than once, the Item_ref has the same ref_item, with the same underlying str_value. Example: SELECT UDF(col1, col1) FROM view_t1; - In such cases, when setting the m_ptr of Item::str_value directly (while processing the second argument), we free the buffer that we had allocated at c_ptr_safe(), at the time of processing the first argument. - As a result, the UDF will try to read a buffer that has been freed, causing the ASAN issue. Solution ======== - The root cause is that the udf_handler changes contents of Item::str_value directly. Instead of doing that, assign the contents of Item::str_value to udf_handler local buffers. Note that this is not a deep string copy. - Any further calls to c_ptr_safe() will not modify Item::str_value object, avoiding the issue. Change-Id: Ib3d6e1d52825dafbc1e495f5f45f8fac75bc90f1
1 parent 0fc1164 commit 889a66a

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

sql/item_func.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4980,19 +4980,28 @@ void udf_handler::get_string(uint index) {
49804980
bool udf_handler::get_and_convert_string(uint index) {
49814981
String *res = args[index]->val_str(&buffers[index]);
49824982

4983-
/* m_args_extension.charset_info[index] is a legitimate charset */
4984-
if (res != nullptr && m_args_extension.charset_info[index] != nullptr) {
4985-
if (res->charset() != m_args_extension.charset_info[index]) {
4983+
if (!args[index]->null_value) {
4984+
auto check_charset = m_args_extension.charset_info[index];
4985+
if (check_charset != nullptr && res->charset() != check_charset) {
4986+
/* m_args_extension.charset_info[index] is a legitimate charset */
49864987
String temp;
49874988
uint dummy;
49884989
if (temp.copy(res->ptr(), res->length(), res->charset(),
49894990
m_args_extension.charset_info[index], &dummy)) {
49904991
return true;
49914992
}
49924993
*res = std::move(temp);
4994+
} else if (res != &buffers[index]) {
4995+
/* The res returned above is &Item::str_value
4996+
* We may call c_ptr_safe() below, reallocating the buffer of
4997+
* Item::str_value If we set the str_value m_ptr directly somewhere, the
4998+
* allocated buffer at c_ptr_safe() will be freed, before the UDF is able
4999+
* to use it. So, instead of changing Item::str_value, copy its contents
5000+
* to udf_handler::buffers and use that instead.
5001+
*/
5002+
buffers[index] = *res;
5003+
res = &buffers[index];
49935004
}
4994-
}
4995-
if (!args[index]->null_value) {
49965005
f_args.args[index] = res->c_ptr_safe();
49975006
f_args.lengths[index] = res->length();
49985007
} else {

0 commit comments

Comments
 (0)