Skip to content

Commit 3281b6b

Browse files
SeanCAdamsgrooverdan
authored andcommitted
MDEV-24507: Server Crash using UDF in WHERE clause of VIEW
These changes are submitted under the BSD 3-clause License. The original ticket describes a server crash when using a UDF in the WHERE clause of a view. The crash also happens when using a UDF in the WHERE clause of a SELECT that uses a sub-query in the FROM clause. When the UDF does not have a _deinit function the server crashes in udf_handler::cleanup (sql/item_func.cc:3467). When the UDF has both an _init and a _deinit function but _init does not allocate memory for initid->ptr the server crashes in udf_handler::cleanup (sql/item_func.cc:3467). When the UDF has both an _init and a _deinit function and allocates/deallocates memory for initid->ptr the server crashes in the memory deallocation of the _deinit function. The sequence of events seen are: 1. A UDF, U, is created for the query. 2. The UDF _init function is called using U->initid. 3. U is cloned for the sub-query using the [default|implicit] copy constructor, resulting in V. 4. The UDF _init function is called using V->initid. U->initid and V->initid are the same value. 5. The UDF function is called. 6. The UDF _deinit function is called using U->initid. If any memory was allocated for initid->ptr it is deallocated here. 7. udf_handler::cleanup deletes the U->buffers String array. 8. The UDF _deinit function is called using V->initid. If any memory was allocated for initid->ptr it was previously deallocated and _deinit crashes the server. 9. udf_handler::cleanup deletes the V->buffers String array. V->buffers was the same values as U->buffers which was already deallocated. The server crashes. The solution is to create a[n explicit] copy constructor for udf_handler which sets not_original to true. Later, not_original is set back to false (0) after udf_handler::fix_fields has set up a new value for initid->ptr.
1 parent b909b52 commit 3281b6b

File tree

4 files changed

+113
-0
lines changed

4 files changed

+113
-0
lines changed

mysql-test/main/udf.result

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,4 +607,68 @@ drop table t1;
607607
DROP FUNCTION avgcost;
608608
DROP FUNCTION avg2;
609609
DROP FUNCTION myfunc_double;
610+
#
611+
# MDEV-24507: Server Crash using UDF in WHERE clause of VIEW
612+
#
613+
CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
614+
create table t1(pk int primary key, a varchar(20));
615+
create table t2(pk int primary key, a varchar(20));
616+
create view v1 as select pk, a from t1 union select pk, a from t2;
617+
insert into t1 values (1, "One"), (3, "Three"), (5, "Five");
618+
insert into t2 values (2, "Dos"), (4, "Quatro"), (6, "Seis");
619+
select pk, myfunc_int(a) from t1;
620+
pk myfunc_int(a)
621+
1 3
622+
3 5
623+
5 4
624+
select pk, myfunc_int(a) from t2;
625+
pk myfunc_int(a)
626+
2 3
627+
4 6
628+
6 4
629+
select pk, myfunc_int(a) from v1;
630+
pk myfunc_int(a)
631+
1 3
632+
3 5
633+
5 4
634+
2 3
635+
4 6
636+
6 4
637+
select pk from t1 where myfunc_int(a) > 4;
638+
pk
639+
3
640+
select pk from (select pk, a from t1) A where myfunc_int(A.a) > 4;
641+
pk
642+
3
643+
set @save_optimizer_switch = @@optimizer_switch;
644+
set optimizer_switch = 'derived_merge=OFF';
645+
select pk, myfunc_int(a) from t1;
646+
pk myfunc_int(a)
647+
1 3
648+
3 5
649+
5 4
650+
select pk, myfunc_int(a) from t2;
651+
pk myfunc_int(a)
652+
2 3
653+
4 6
654+
6 4
655+
select pk, myfunc_int(a) from v1;
656+
pk myfunc_int(a)
657+
1 3
658+
3 5
659+
5 4
660+
2 3
661+
4 6
662+
6 4
663+
select pk from t1 where myfunc_int(a) > 4;
664+
pk
665+
3
666+
select pk from (select pk, a from t1) A where myfunc_int(A.a) > 4;
667+
pk
668+
3
669+
set optimizer_switch = @save_optimizer_switch;
670+
drop view v1;
671+
drop table t2;
672+
drop table t1;
673+
drop function myfunc_int;
610674
# End of 10.4 tests

mysql-test/main/udf.test

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,4 +647,38 @@ DROP FUNCTION avgcost;
647647
DROP FUNCTION avg2;
648648
DROP FUNCTION myfunc_double;
649649

650+
--echo #
651+
--echo # MDEV-24507: Server Crash using UDF in WHERE clause of VIEW
652+
--echo #
653+
654+
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
655+
eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
656+
657+
create table t1(pk int primary key, a varchar(20));
658+
create table t2(pk int primary key, a varchar(20));
659+
create view v1 as select pk, a from t1 union select pk, a from t2;
660+
661+
insert into t1 values (1, "One"), (3, "Three"), (5, "Five");
662+
insert into t2 values (2, "Dos"), (4, "Quatro"), (6, "Seis");
663+
664+
select pk, myfunc_int(a) from t1;
665+
select pk, myfunc_int(a) from t2;
666+
select pk, myfunc_int(a) from v1;
667+
select pk from t1 where myfunc_int(a) > 4;
668+
select pk from (select pk, a from t1) A where myfunc_int(A.a) > 4;
669+
670+
set @save_optimizer_switch = @@optimizer_switch;
671+
set optimizer_switch = 'derived_merge=OFF';
672+
select pk, myfunc_int(a) from t1;
673+
select pk, myfunc_int(a) from t2;
674+
select pk, myfunc_int(a) from v1;
675+
select pk from t1 where myfunc_int(a) > 4;
676+
select pk from (select pk, a from t1) A where myfunc_int(A.a) > 4;
677+
678+
set optimizer_switch = @save_optimizer_switch;
679+
drop view v1;
680+
drop table t2;
681+
drop table t1;
682+
drop function myfunc_int;
683+
650684
--echo # End of 10.4 tests

sql/item_func.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3547,6 +3547,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
35473547
initid.const_item=func->const_item_cache;
35483548
initid.decimals=func->decimals;
35493549
initid.ptr=0;
3550+
not_original=0;
35503551
for (uint i1= 0 ; i1 < arg_count ; i1++)
35513552
buffers[i1].set_thread_specific();
35523553

sql/sql_udf.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ class udf_handler :public Sql_alloc
147147
*null_value= (my_bool) (is_null || error);
148148
}
149149
String *val_str(String *str,String *save_str);
150+
151+
udf_handler(const udf_handler &orig)
152+
{
153+
u_d = orig.u_d;
154+
buffers = orig.buffers;
155+
f_args = orig.f_args;
156+
initid = orig.initid;
157+
num_buffer = orig.num_buffer;
158+
error = orig.error;
159+
is_null = orig.is_null;
160+
initialized = orig.initialized;
161+
args = orig.args;
162+
not_original = true;
163+
}
150164
};
151165

152166

0 commit comments

Comments
 (0)