From 0e92a685891083c15e23644ce0a6c1ff3f2400d0 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Wed, 14 Jan 2015 15:29:27 +0100 Subject: [PATCH] (Corrected) Fix for CONC-118: memory leak when reconnecting --- libmariadb/libmariadb.c | 11 +++++++---- unittest/libmariadb/connection.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index 2f3aa212..701f1ac8 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -2022,11 +2022,12 @@ static my_bool mysql_reconnect(MYSQL *mysql) } tmp_mysql.reconnect= mysql->reconnect; - bzero((char*) &mysql->options,sizeof(mysql->options)); if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) { + /* don't free options (CONC-118) */ + memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options)); my_set_error(mysql, tmp_mysql.net.last_errno, tmp_mysql.net.sqlstate, tmp_mysql.net.last_error); @@ -2046,14 +2047,16 @@ static my_bool mysql_reconnect(MYSQL *mysql) stmt->state= MYSQL_STMT_INITTED; SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); } - else - tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list); } + tmp_mysql.free_me= mysql->free_me; + tmp_mysql.stmts= mysql->stmts; + + /* Don't free options, we moved them to tmp_mysql */ + memset(&mysql->options, 0, sizeof(mysql->options)); mysql->free_me=0; mysql->stmts= NULL; mysql_close(mysql); - memset(&mysql->options, 0, sizeof(mysql->options)); *mysql=tmp_mysql; mysql->reconnect= 1; net_clear(&mysql->net); diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index ef13161f..31cf17dc 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -638,7 +638,39 @@ int test_connection_timeout(MYSQL *my) return OK; } +/* test should run with valgrind */ +static int test_conc118(MYSQL *mysql) +{ + int rc; + + mysql->reconnect= 1; + mysql->options.unused_1= 1; + + rc= mysql_kill(mysql, mysql_thread_id(mysql)); + sleep(2); + + rc= mysql_query(mysql, "SET @a:=1"); + check_mysql_rc(rc, mysql); + + FAIL_IF(mysql->options.unused_1 != 1, "options got lost"); + + rc= mysql_kill(mysql, mysql_thread_id(mysql)); + sleep(2); + + mysql->host= "foo"; + + rc= mysql_query(mysql, "SET @a:=1"); + FAIL_IF(!rc, "error expected"); + + mysql->host= hostname; + rc= mysql_query(mysql, "SET @a:=1"); + check_mysql_rc(rc, mysql); + + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc118", test_conc118, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc66", test_conc66, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_bug20023", test_bug20023, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_bug31669", test_bug31669, TEST_CONNECTION_NEW, 0, NULL, NULL},