From e42dd6c0e0d1d3406cc784ff7949b352b58c40d7 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Sat, 28 Oct 2017 16:46:49 +0200 Subject: [PATCH] Fix for MDEV-14165: - The metadata length value for a column with a zerofill flag was calculated with a fixed length instead of using the reported length. - fixed a possible stackoverflow, if the display width for a column with zerofill flag is greater then 22. (libmysql ps implementation truncates the result after 21 digits and reports truncation error). --- libmariadb/ma_stmt_codec.c | 4 +-- libmariadb/mariadb_stmt.c | 10 ++++++- unittest/libmariadb/ps_bugs.c | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/libmariadb/ma_stmt_codec.c b/libmariadb/ma_stmt_codec.c index 72ea9653..e90666cf 100644 --- a/libmariadb/ma_stmt_codec.c +++ b/libmariadb/ma_stmt_codec.c @@ -377,10 +377,11 @@ static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, lon break; default: { - char buffer[22]; + char *buffer; char *endptr; uint len; + buffer= alloca(MAX(field->length, 22)); endptr= ma_ll2str(val, buffer, is_unsigned ? 10 : -10); len= (uint)(endptr - buffer); @@ -392,7 +393,6 @@ static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, lon memset((char*) buffer, '0', field->length - len); len= field->length; } - convert_froma_string(r_param, buffer, len); } break; diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index d3eb0421..6371ef87 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -242,8 +242,16 @@ int mthd_stmt_read_all_rows(MYSQL_STMT *stmt) } else { - if (!stmt->fields[i].max_length) + if (stmt->fields[i].flags & ZEROFILL_FLAG) + { + size_t len= MAX(stmt->fields[i].length, mysql_ps_fetch_functions[stmt->fields[i].type].max_len); + if (len > stmt->fields[i].max_length) + stmt->fields[i].max_length= len; + } + else if (!stmt->fields[i].max_length) + { stmt->fields[i].max_length= mysql_ps_fetch_functions[stmt->fields[i].type].max_len; + } cp+= mysql_ps_fetch_functions[stmt->fields[i].type].pack_len; } } diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index ba13b660..a5342f8f 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -4580,7 +4580,62 @@ static int test_conc208(MYSQL *mysql) return OK; } +static int test_mdev14165(MYSQL *mysql) +{ + int rc; + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + MYSQL_FIELD *fields; + MYSQL_RES *result; + my_bool val= 1; + MYSQL_BIND bind[1]; + char buf1[52]; + + rc= mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, &val); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + rc= mysql_query(mysql, "CREATE TABLE t1 (i INT(20) ZEROFILL)"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (2),(1)"); + check_mysql_rc(rc, mysql); + rc= mysql_stmt_prepare(stmt, "SELECT i FROM t1", -1); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + memset(bind, 0, sizeof(MYSQL_BIND)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer_length= 51; + bind[0].buffer= buf1; + + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &val); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_store_result(stmt); + check_stmt_rc(rc, stmt); + + result= mysql_stmt_result_metadata(stmt); + + fields= mysql_fetch_fields(result); + + FAIL_IF(fields[0].length < 20, "Expected length=20"); + FAIL_IF(fields[0].max_length < 20, "Expected max_length=20"); + + mysql_stmt_fetch(stmt); + + FAIL_UNLESS(strcmp(buf1, "00000000000000000002") == 0, "Wrong result"); + mysql_free_result(result); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + check_mysql_rc(rc, mysql); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_mdev14165", test_mdev14165, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc217", test_conc217, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc205", test_conc205, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},