Skip to content

Commit 5b7c98e

Browse files
committed
BUG#36314928 - Assertion failure !s.uses_buffer_owned_by(this) in sql_string.cc
BUG#36389091 - `!s.uses_buffer_owned_by(this)' in String::append at sql-common/sql_string.cc BUG#36397496 - HLL query gives Assertion `!str || str != m_ptr' failed Problem ======= In udf_handler::get_and_convert_string, we use udf_handler::buffers to hold pointers returned by val_str(...) calls. This causes an issue with certain functions (such as Item_func_concat), which expect the argument passed in val_str(...) to be non-overlapping to their local buffers. Sequence of steps leading to the issue: 1. First call of udf_handler::get_and_convert_string: We call Item_func_concat::val_str with buffers[0].m_ptr: 0x0. 2. Item_func_concat::val_str returns the address of its local &tmp_value as res. res->m_ptr: ADDR1 3. We copy *res to buffers[0]. buffers[0].m_ptr: ADDR1 4. Second call of udf_handler::get_and_convert_string: We call Item_func_concat::val_str with buffers[0].m_ptr: ADDR1 5. Item_func_concat::val_str sees that buffers[0].m_ptr and its local tmp_value.m_ptr are the same ADDR1 -> assert fails. Solution ======== - Introduce udf_handler::arg_buffers to hold data returned by val_str(...) in get_and_convert_string. The current way of modifying *res itself is risky, since it could be changing Item::str_value object, which has other implications (BUG#36297142) - Instead of using udf_handler::buffers to hold pointers returned, do a deep copy to udf_handler::arg_buffers. Change-Id: I50c2a36cd609dc28e70cabe6c730b15bac6ef8d6
1 parent a032f4a commit 5b7c98e

File tree

2 files changed

+16
-23
lines changed

2 files changed

+16
-23
lines changed

sql/item_func.cc

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4593,6 +4593,7 @@ void udf_handler::clean_buffers() {
45934593
if (buffers == nullptr) return;
45944594
for (uint i = 0; i < f_args.arg_count; i++) {
45954595
buffers[i].mem_free();
4596+
arg_buffers[i].mem_free();
45964597
}
45974598
}
45984599

@@ -4703,6 +4704,8 @@ bool udf_handler::fix_fields(THD *thd, Item_result_field *func, uint arg_count,
47034704
// if (!(buffers = new String[arg_count]) ||
47044705
if (!(buffers = pointer_cast<String *>(
47054706
(*THR_MALLOC)->Alloc(sizeof(String) * arg_count))) ||
4707+
!(arg_buffers = pointer_cast<String *>(
4708+
(*THR_MALLOC)->Alloc(sizeof(String) * arg_count))) ||
47064709
!(f_args.args =
47074710
(char **)(*THR_MALLOC)->Alloc(arg_count * sizeof(char *))) ||
47084711
!(f_args.lengths =
@@ -4723,6 +4726,7 @@ bool udf_handler::fix_fields(THD *thd, Item_result_field *func, uint arg_count,
47234726
}
47244727
for (uint i = 0; i < arg_count; i++) {
47254728
(void)::new (buffers + i) String;
4729+
(void)::new (arg_buffers + i) String;
47264730
m_args_extension.charset_info[i] = nullptr;
47274731
}
47284732

@@ -5044,29 +5048,17 @@ bool udf_handler::get_and_convert_string(uint index) {
50445048
String *res = args[index]->val_str(&buffers[index]);
50455049

50465050
if (!args[index]->null_value) {
5047-
auto check_charset = m_args_extension.charset_info[index];
5048-
if (check_charset != nullptr && res->charset() != check_charset) {
5049-
/* m_args_extension.charset_info[index] is a legitimate charset */
5050-
String temp;
5051-
uint dummy;
5052-
if (temp.copy(res->ptr(), res->length(), res->charset(),
5053-
m_args_extension.charset_info[index], &dummy)) {
5054-
return true;
5055-
}
5056-
*res = std::move(temp);
5057-
} else if (res != &buffers[index]) {
5058-
/* The res returned above is &Item::str_value
5059-
* We may call c_ptr_safe() below, reallocating the buffer of
5060-
* Item::str_value If we set the str_value m_ptr directly somewhere, the
5061-
* allocated buffer at c_ptr_safe() will be freed, before the UDF is able
5062-
* to use it. So, instead of changing Item::str_value, copy its contents
5063-
* to udf_handler::buffers and use that instead.
5064-
*/
5065-
buffers[index] = *res;
5066-
res = &buffers[index];
5067-
}
5068-
f_args.args[index] = res->c_ptr_safe();
5069-
f_args.lengths[index] = res->length();
5051+
uint errors = 0;
5052+
if (arg_buffers[index].copy(res->ptr(), res->length(), res->charset(),
5053+
m_args_extension.charset_info[index],
5054+
&errors)) {
5055+
return true;
5056+
}
5057+
if (errors) {
5058+
return true;
5059+
}
5060+
f_args.args[index] = arg_buffers[index].c_ptr_safe();
5061+
f_args.lengths[index] = arg_buffers[index].length();
50705062
} else {
50715063
f_args.lengths[index] = 0;
50725064
}

sql/sql_udf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class udf_handler {
8484
protected:
8585
udf_func *u_d;
8686
String *buffers{nullptr};
87+
String *arg_buffers{nullptr};
8788
UDF_ARGS f_args;
8889
UDF_INIT initid;
8990
char *num_buffer{nullptr};

0 commit comments

Comments
 (0)