From 563ad6c470ea5bf235f45f14f52d8f1df0040488 Mon Sep 17 00:00:00 2001 From: Alexandr Kuznetsov Date: Fri, 27 Sep 2024 13:23:20 +0300 Subject: [PATCH] Fix for issue #47 - double free of COL_INFO object (#48) * Fix for issue #47 - double free of COL_INFO object due to refcount breakage during reuse of directly found object in getColumnsInfo(...). One more possible memory leak of COL_INFO objects in getColumnsInfo(...). Signed-off-by: Alexandr Kuznetsov * Fix spelling mistake in comment. Signed-off-by: Alexandr Kuznetsov --------- Signed-off-by: Alexandr Kuznetsov --- .gitignore | 7 +++++++ connection.c | 1 + parse.c | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bd35adfd..c7a61dfe 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ windows-local.mak /Makefile.in /aclocal.m4 /autom4te.cache/ +/autom4te.cache/* /config/ /config.h /config.h.in @@ -43,6 +44,7 @@ windows-local.mak /config.status /configure /libtool +/psqlodbca.la /psqlodbcw.la /stamp-h1 @@ -107,6 +109,11 @@ bld/ [Ll]og/ [Ll]ogs/ +# Eclipse project options +/.project +/.cproject +/.settings + # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot diff --git a/connection.c b/connection.c index d83e9acd..7837dbb9 100644 --- a/connection.c +++ b/connection.c @@ -556,6 +556,7 @@ CC_clear_col_info(ConnectionClass *self, BOOL destroy) /* Going through COL_INFO cache table and releasing coli objects. */ if (coli = self->col_info[i], NULL != coli) { + MYLOG(0, "!!!refcnt %p:%d -> %d\n", coli, coli->refcnt, coli->refcnt - 1); coli->refcnt--; if (coli->refcnt <= 0) { diff --git a/parse.c b/parse.c index f63f3fc6..a8445afd 100644 --- a/parse.c +++ b/parse.c @@ -829,7 +829,7 @@ getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementCla { BOOL coli_exist = FALSE; COL_INFO *coli = NULL, *ccoli = NULL, *tcoli; - int k; + int k, tmp_refcnt = 0; time_t acctime = 0; MYLOG(0, " Success\n"); @@ -882,6 +882,8 @@ getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementCla if (coli_exist) { /* We have ready to use coli object. Cleaning it. */ + tmp_refcnt = coli->refcnt; /* If we found coli with greloid, then some TABLE_INFO objects may have references to it -> save refcnt for them. */ + tmp_refcnt--; /* Down the road we will increase refcnt again to account for the reference from ConnectionClass object to coli object. */ free_col_info_contents(coli); } else @@ -921,6 +923,7 @@ getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementCla } col_info_initialize(coli); + coli->refcnt = tmp_refcnt; coli->refcnt++; /* Counting one reference to coli object from connection COL_INFO cache table. */ coli->result = res; if (res && QR_get_num_cached_tuples(res) > 0) @@ -976,6 +979,17 @@ MYLOG(DETAIL_LOG_LEVEL, "oid item == %s\n", (const char *) QR_get_value_backend_ MYLOG(0, "Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables); /* Associate a table from the statement with a SQLColumn info */ found = TRUE; + if (wti->col_info) + { + /* wti also has reference to COL_INFO object, so we must release it. */ +MYLOG(0, "!!!refcnt %p:%d -> %d\n", wti->col_info, wti->col_info->refcnt, wti->col_info->refcnt - 1); + wti->col_info->refcnt--; + if (wti->col_info->refcnt <= 0) + { + free_col_info_contents(wti->col_info); + free(wti->col_info); + } + } coli->refcnt++; /* Counting another one reference to coli object from TABLE_INFO wti object. */ wti->col_info = coli; }