From 7a452efb5887e13ca7dc7c878b4916ddcecacd12 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Fri, 12 Apr 2013 11:24:42 +0200 Subject: [PATCH] Fixed memory overrun (wrong length calculation in mysql_stmt_generate_request) Fuxed crash with mysql_send_long_data --- libmariadb/my_stmt.c | 14 ++++++-- unittest/libmariadb/ps.c | 70 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/libmariadb/my_stmt.c b/libmariadb/my_stmt.c index b3f6974b..da8a1e85 100644 --- a/libmariadb/my_stmt.c +++ b/libmariadb/my_stmt.c @@ -504,7 +504,7 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req n data from bind_buffer */ - size_t length= 9000; + size_t length= 1024; size_t free_bytes= 0; size_t data_size= 0; uint i; @@ -513,6 +513,16 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req DBUG_ENTER("mysql_stmt_execute_generate_request"); + /* calculate length */ + for (i=0; i < stmt->param_count; i++) + { + if (!stmt->params[i].long_data_used) + length+= stmt->params[i].buffer_length ? + stmt->params[i].buffer_length + 1 : + stmt->params[i].buffer_type ? + mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len + 1 : 1; + } + if (!(start= p= (uchar *)my_malloc(length, MYF(MY_WME | MY_ZEROFILL)))) goto mem_error; @@ -573,7 +583,7 @@ unsigned char* mysql_stmt_execute_generate_request(MYSQL_STMT *stmt, size_t *req stmt->params[i].is_null = &is_not_null; if (!stmt->params[i].length) stmt->params[i].length= &stmt->params[i].length_value; - if (!*stmt->params[i].is_null && !stmt->params[i].long_data_used) + if (!stmt->params[i].is_null && !stmt->params[i].long_data_used) { switch (stmt->params[i].buffer_type) { case MYSQL_TYPE_NULL: diff --git a/unittest/libmariadb/ps.c b/unittest/libmariadb/ps.c index 48f4ae2f..d472322e 100644 --- a/unittest/libmariadb/ps.c +++ b/unittest/libmariadb/ps.c @@ -4590,7 +4590,77 @@ static int test_new_date(MYSQL *mysql) return OK; } +static int test_long_data1(MYSQL *mysql) +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + MYSQL_BIND bind[1]; + char query[MAX_TEST_QUERY_LENGTH]; + char *data= "12345"; + + rc= mysql_autocommit(mysql, TRUE); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS tld"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE tld (col1 int, " + "col2 long varbinary)"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "INSERT INTO tld VALUES (1,'test')"); + check_mysql_rc(rc, mysql); + + strcpy(query, "UPDATE tld SET col2=? WHERE col1=1"); + stmt= mysql_stmt_init(mysql); + FAIL_IF(!stmt, mysql_error(mysql)); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_stmt_rc(rc, stmt); + bind[0].buffer_type= MYSQL_TYPE_STRING; + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_send_long_data(stmt, 0, data, 6); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_close(stmt); + check_stmt_rc(rc, stmt); + return OK; +} + +int test_blob_9000(MYSQL *mysql) +{ + MYSQL_BIND bind[1]; + MYSQL_STMT *stmt; + int rc; + char buffer[9200]; + char *query= "INSERT INTO tb9000 VALUES (?)"; + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS tb9000"); + check_mysql_rc(rc, mysql); + rc= mysql_query(mysql, "CREATE TABLE tb9000 (a blob)"); + check_mysql_rc(rc, mysql); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + + memset(bind, 0, sizeof(MYSQL_BIND)); + memset(buffer, 'C', 9200); + bind[0].buffer= buffer; + bind[0].buffer_length= 9200; + bind[0].buffer_type= MYSQL_TYPE_STRING; + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + mysql_stmt_close(stmt); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_blob_9000", test_blob_9000, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, + {"test_long_data1", test_long_data1, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, {"test_prepare_insert_update", test_prepare_insert_update, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, {"test_prepare_simple", test_prepare_simple, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, {"test_prepare_syntax", test_prepare_syntax, TEST_CONNECTION_DEFAULT, 0, NULL , NULL},