summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2020-05-12 19:45:21 +0400
committerAlexander Barkov <bar@mariadb.com>2020-05-12 19:45:21 +0400
commit9f20968169e21fcf8941041a8a7ce06013a79bd9 (patch)
treeae3fa2cf852ab1a2f2dd393851d6d37a801fa421
parentdb537a8372dea05ddfe10fbd5c317214658bfdbd (diff)
downloadmariadb-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.cc16
-rw-r--r--tests/mysql_client_test.c48
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 }
};