From 4cf222c082950ff6a713792f68e2a2882135199e Mon Sep 17 00:00:00 2001 From: Bogdan Degtyariov Date: Wed, 4 Sep 2013 16:46:27 +1000 Subject: [PATCH] Memory leak in SQLPrepare with queries that use parameters (Bug# 17400483/70113) - no test case --- ChangeLog | 2 ++ driver/catalog_no_i_s.c | 1 + driver/my_prepared_stmt.c | 21 ++++++++++++++------- driver/my_stmt.c | 35 ++++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/driver/catalog_no_i_s.c b/driver/catalog_no_i_s.c index ac54d3e..be4d616 100644 --- a/driver/catalog_no_i_s.c +++ b/driver/catalog_no_i_s.c @@ -2141,6 +2141,7 @@ mysql_tables(SQLHSTMT hstmt, if (!row_count) { mysql_free_result(stmt->result); + stmt->result= NULL; goto empty_set; } diff --git a/driver/my_prepared_stmt.c b/driver/my_prepared_stmt.c index 71a5648..126d892 100644 --- a/driver/my_prepared_stmt.c +++ b/driver/my_prepared_stmt.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012-2013, Oracle and/or its affiliates. All rights reserved. The MySQL Connector/ODBC is licensed under the terms of the GPLv2 , like most @@ -223,10 +223,17 @@ void free_result_bind(STMT *stmt) { if (stmt->result_bind != NULL) { + int i, field_cnt= field_count(stmt); + x_free(stmt->result_bind[0].is_null); x_free(stmt->result_bind[0].length); x_free(stmt->result_bind[0].error); - x_free(stmt->result_bind[0].buffer); + + /* buffer was allocated for each column */ + for (i= 0; i < field_cnt; i++) + { + x_free(stmt->result_bind[i].buffer); + } x_free(stmt->result_bind); stmt->result_bind= 0; @@ -438,11 +445,11 @@ int ssps_bind_result(STMT *stmt) IS_PS_OUT_PARAMS(stmt)); stmt->result_bind[i].buffer_type = p.type; - stmt->result_bind[i].buffer = p.buffer; - stmt->result_bind[i].buffer_length= (unsigned long)p.size; - stmt->result_bind[i].length = &len[i]; - stmt->result_bind[i].is_null = &is_null[i]; - stmt->result_bind[i].error = &err[i]; + stmt->result_bind[i].buffer = p.buffer; + stmt->result_bind[i].buffer_length= (unsigned long)p.size; + stmt->result_bind[i].length = &len[i]; + stmt->result_bind[i].is_null = &is_null[i]; + stmt->result_bind[i].error = &err[i]; stmt->result_bind[i].is_unsigned = (field->flags & UNSIGNED_FLAG)? 1: 0; stmt->array[i]= p.buffer; diff --git a/driver/my_stmt.c b/driver/my_stmt.c index 0dd059f..6e201d5 100644 --- a/driver/my_stmt.c +++ b/driver/my_stmt.c @@ -44,7 +44,16 @@ BOOL returned_result(STMT *stmt) if (ssps_used(stmt)) { /* Basically at this point we are supposed to get result already */ - return stmt->result ? TRUE : mysql_stmt_result_metadata(stmt->ssps) != NULL; + MYSQL_RES *temp_res= NULL; + + if ((stmt->result != NULL) || + (temp_res= mysql_stmt_result_metadata(stmt->ssps)) != NULL) + { + /* mysql_free_result checks for NULL, so we can always call it */ + mysql_free_result(temp_res); + return TRUE; + } + return FALSE; } else { @@ -55,24 +64,18 @@ BOOL returned_result(STMT *stmt) my_bool free_current_result(STMT *stmt) { + my_bool res= 0; if (returned_result(stmt)) { if (ssps_used(stmt)) - - { - my_bool res= mysql_stmt_free_result(stmt->ssps); - stmt->result= NULL; - - return res; - } - else { - mysql_free_result(stmt->result); - stmt->result= NULL; - return '\0'; + res= mysql_stmt_free_result(stmt->ssps); } + /* We need to always free stmt->result because SSPS keep metadata there */ + mysql_free_result(stmt->result); + stmt->result= NULL; } - return '\0'; + return res; } @@ -98,6 +101,9 @@ MYSQL_RES * stmt_get_result(STMT *stmt, BOOL force_use) we need to use/store each resultset of multiple resultsets */ MYSQL_RES * get_result_metadata(STMT *stmt, BOOL force_use) { + /* just a precaution, mysql_free_result checks for NULL anywat */ + mysql_free_result(stmt->result); + if (ssps_used(stmt)) { stmt->result= mysql_stmt_result_metadata(stmt->ssps); @@ -399,6 +405,9 @@ SQLRETURN prepare(STMT *stmt, char * query, SQLINTEGER query_length) stmt->param_count= mysql_stmt_param_count(stmt->ssps); + /* make sure we free the result from the previous time */ + mysql_free_result(stmt->result); + /* Getting result metadata */ if ((stmt->result= mysql_stmt_result_metadata(stmt->ssps))) { -- 2.13.3