diff options
author | Alexander Barkov <bar@mariadb.com> | 2020-05-12 19:45:21 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2020-05-12 19:45:21 +0400 |
commit | 9f20968169e21fcf8941041a8a7ce06013a79bd9 (patch) | |
tree | ae3fa2cf852ab1a2f2dd393851d6d37a801fa421 | |
parent | db537a8372dea05ddfe10fbd5c317214658bfdbd (diff) | |
download | mariadb-git-9f20968169e21fcf8941041a8a7ce06013a79bd9.tar.gz |
MDEV-20261 NULL passed to String::eq, SEGV, server crash, regression in 10.4
Type_handler_xxx::Item_const_eq() can handle only non-NULL values.
The code in Item_basic_value::eq() did not take this into account.
Adding a test to detect three different combinations:
- Both values are NULLs, return true.
- Only one value is NULL, return false.
- Both values are not NULL, call Type_handler::Item_const_eq()
to check equality.
-rw-r--r-- | sql/item.cc | 16 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 48 |
2 files changed, 62 insertions, 2 deletions
diff --git a/sql/item.cc b/sql/item.cc index 69524cf8116..6fe62c8c6ec 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3477,8 +3477,20 @@ bool Item_basic_value::eq(const Item *item, bool binary_cmp) const (h0= type_handler())->type_handler_for_comparison() == (h1= item->type_handler())->type_handler_for_comparison() && h0->cast_to_int_type_handler()->type_handler_for_comparison() == - h1->cast_to_int_type_handler()->type_handler_for_comparison() && - h0->Item_const_eq(c0, c1, binary_cmp); + h1->cast_to_int_type_handler()->type_handler_for_comparison(); + if (res) + { + switch (c0->const_is_null() + c1->const_is_null()) { + case 2: // Two NULLs + res= true; + break; + case 1: // NULL and non-NULL + res= false; + break; + case 0: // Two non-NULLs + res= h0->Item_const_eq(c0, c1, binary_cmp); + } + } DBUG_EXECUTE_IF("Item_basic_value", push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_NOTE, diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 16bfa72985f..923e4d01ca2 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -20886,6 +20886,53 @@ static void test_explain_meta() mct_close_log(); } + +/* + MDEV-20261 NULL passed to String::eq, SEGV, server crash, regression in 10.4 +*/ +static void test_mdev20261() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND param[1]; + const char *query= "SELECT * FROM t1 WHERE f = ? OR f = 'foo'"; + char val[]= ""; + my_bool is_null= TRUE; + + myheader("test_mdev20261"); + + rc= mysql_query(mysql, "CREATE OR REPLACE TABLE t1 (f varchar(64)) ENGINE=MyISAM"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + verify_param_count(stmt, 1); + + bzero((char*) param, sizeof(param)); + + param[0].buffer= &val; + param[0].buffer_type= MYSQL_TYPE_STRING; + param[0].is_null= &is_null; + + rc= mysql_stmt_bind_param(stmt, param); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + myquery(rc); +} + + static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -21179,6 +21226,7 @@ static struct my_tests_st my_tests[]= { #endif { "test_explain_meta", test_explain_meta }, { "test_mdev18408", test_mdev18408 }, + { "test_mdev20261", test_mdev20261 }, { 0, 0 } }; |