From e7924df06ace8937b3d4f42728f92d1bf4032990 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Tue, 14 Sep 2010 22:27:07 -0700 Subject: [PATCH] make sure we only attempt to close/free the MYSQL pointer once --- ext/mysql2/client.c | 33 +++++++++++++++++++-------------- ext/mysql2/client.h | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 44e87f3..395728b 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -8,8 +8,8 @@ static VALUE intern_encoding_from_charset; static ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array; static ID intern_merge, intern_error_number_eql, intern_sql_state_eql; -#define REQUIRE_OPEN_DB(_ctxt) \ - if(!_ctxt->net.vio) { \ +#define REQUIRE_OPEN_DB(wrapper) \ + if(wrapper->closed || !wrapper->client->net.vio) { \ rb_raise(cMysql2Error, "closed MySQL connection"); \ return Qnil; \ } @@ -130,14 +130,18 @@ static void rb_mysql_client_free(void * ptr) { } /* It's safe to call mysql_close() on an already closed connection. */ - mysql_close(wrapper->client); + if (!wrapper->closed) { + mysql_close(wrapper->client); + } xfree(ptr); } static VALUE nogvl_close(void * ptr) { - MYSQL *client = (MYSQL *)ptr; - mysql_close(client); - client->net.fd = -1; + mysql_client_wrapper *wrapper = ptr; + if (!wrapper->closed) { + mysql_close(wrapper->client); + wrapper->closed = 1; + } return Qnil; } @@ -147,6 +151,7 @@ static VALUE allocate(VALUE klass) { obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper); wrapper->encoding = Qnil; wrapper->active = 0; + wrapper->closed = 0; return obj; } @@ -180,7 +185,7 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po static VALUE rb_mysql_client_close(VALUE self) { GET_CLIENT(self); - rb_thread_blocking_region(nogvl_close, wrapper->client, RUBY_UBF_IO, 0); + rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0); return Qnil; } @@ -223,7 +228,7 @@ static VALUE rb_mysql_client_async_result(VALUE self) { MYSQL_RES * result; GET_CLIENT(self); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) { // an error occurred, mark this connection inactive MARK_CONN_INACTIVE(self); @@ -262,7 +267,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) { VALUE opts, defaults; GET_CLIENT(self); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); args.mysql = wrapper->client; // see if this connection is still waiting on a result from a previous query @@ -340,7 +345,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) { oldLen = RSTRING_LEN(str); newStr = rb_str_new(0, oldLen*2+1); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen); if (newLen == oldLen) { // no need to return a new ruby string if nothing changed @@ -385,7 +390,7 @@ static VALUE rb_mysql_client_server_info(VALUE self) { rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding); #endif - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); version = rb_hash_new(); rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client))); @@ -402,19 +407,19 @@ static VALUE rb_mysql_client_server_info(VALUE self) { static VALUE rb_mysql_client_socket(VALUE self) { GET_CLIENT(self); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); return INT2NUM(wrapper->client->net.fd); } static VALUE rb_mysql_client_last_id(VALUE self) { GET_CLIENT(self); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); return ULL2NUM(mysql_insert_id(wrapper->client)); } static VALUE rb_mysql_client_affected_rows(VALUE self) { GET_CLIENT(self); - REQUIRE_OPEN_DB(wrapper->client); + REQUIRE_OPEN_DB(wrapper); return ULL2NUM(mysql_affected_rows(wrapper->client)); } diff --git a/ext/mysql2/client.h b/ext/mysql2/client.h index 781ccda..d5c2993 100644 --- a/ext/mysql2/client.h +++ b/ext/mysql2/client.h @@ -34,6 +34,7 @@ void init_mysql2_client(); typedef struct { VALUE encoding; short int active; + short int closed; MYSQL *client; } mysql_client_wrapper;