[Devel] memory leak and misc fixes to unixodbc
S G
skg1010 at hotmail.com
Thu Apr 6 20:01:45 CEST 2006
Hi
I've corrected some issues with unixodbc module leaking memory in the covert
rows function. I've also removed some deprecated ODBC functions, fixed
invalid cursort state on error and fixed error reporting from ODBC. The
module tests and works properly now. Attached is the patch.
-Sumeet Gupta
_________________________________________________________________
Dont just search. Find. Check out the new MSN Search!
http://search.msn.click-url.com/go/onm00200636ave/direct/01/
-------------- next part --------------
cvs diff: Diffing modules/unixodbc-SG
Index: modules/unixodbc-SG/dbase.c
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/dbase.c,v
retrieving revision 1.3
diff -u -r1.3 dbase.c
--- modules/unixodbc-SG/dbase.c 1 Mar 2006 10:13:37 -0000 1.3
+++ modules/unixodbc-SG/dbase.c 6 Apr 2006 17:40:24 -0000
@@ -25,6 +25,8 @@
* History:
* --------
* 2005-12-01 initial commit (chgen)
+ * 2006-04-03 fixed invalid handle to extract error (sgupta)
+ * 2006-04-04 removed deprecated ODBC functions, closed cursors on error
(sgupta)
*/
@@ -52,32 +54,80 @@
static int submit_query(db_con_t* _h, const char* _s)
{
int ret;
+ SQLCHAR outstr[1024];
+ SQLSMALLINT outstrlen;
+ SQLCHAR sqlstate[15];
+ SQLCHAR ErrorMsg[SQL_MAX_MESSAGE_LENGTH+1];
+ SQLINTEGER native_error = 0;
+ char conn_str[MAX_CONN_STR_LEN];
+ SQLRETURN sts;
/* first do some cleanup if required */
if(CON_RESULT(_h))
{
- SQLFreeStmt(&CON_RESULT(_h), SQL_RESET_PARAMS);
- SQLFreeStmt(&CON_RESULT(_h), SQL_UNBIND);
- SQLFreeStmt(&CON_RESULT(_h), SQL_CLOSE);
- SQLFreeStmt(&CON_RESULT(_h), SQL_DROP);
+ SQLCloseCursor(CON_RESULT(_h));
+ SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
}
- ret = SQLAllocStmt(CON_CONNECTION(_h), &CON_RESULT(_h));
- if (!SQL_SUCCEEDED(ret))
- {
- LOG(L_ERR, "Statement allocation error %d\n",
- (int)(long)CON_CONNECTION(_h));
- extract_error("SQLAllocStmt", CON_CONNECTION(_h),
SQL_HANDLE_DBC);
- return ret;
- }
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h),
&CON_RESULT(_h));
+ if (!SQL_SUCCEEDED(ret))
+ {
+ LOG(L_ERR, "ERROR:unixodbc:submit_query: Statement allocation
error %d\n",
+ (int)(long)CON_CONNECTION(_h));
+ extract_error("SQLAllocStmt", CON_CONNECTION(_h),
SQL_HANDLE_DBC);
+
+ sts = SQLError (CON_ENV(_h), CON_CONNECTION(_h), SQL_NULL_HSTMT,
sqlstate, &native_error,
+ ErrorMsg, sizeof(ErrorMsg), NULL);
+ if (SQL_SUCCEEDED (sts) &&
+ strncmp(sqlstate,"08003",5)!=0 && /* Connect not open */
+ strncmp(sqlstate,"08S01",5)!=0) /* Communication link
failure */
+ {
+ return ret;
+ }
+
+ LOG(L_ERR, "ERROR:unixodbc:submit_query: try to reconnect\n");
+
+ // Disconnect
+ SQLDisconnect (CON_CONNECTION(_h));
+
+ // Reconnect
+ if (!build_conn_str(CON_ID(_h), conn_str)) {
+ LOG(L_ERR, "ERROR:unixodbc:submit_query: failed to build
connection string\n");
+ return ret;
+ }
+
+ ret = SQLDriverConnect(CON_CONNECTION(_h), (void *)1,
(SQLCHAR*)conn_str,
+ SQL_NTS, outstr, sizeof(outstr),
&outstrlen,
+ SQL_DRIVER_COMPLETE);
+ if (!SQL_SUCCEEDED(ret)) {
+ LOG(L_ERR, "ERROR:unixodbc:submit_query: failed to
connect\n");
+ extract_error("SQLDriverConnect", CON_CONNECTION(_h),
SQL_HANDLE_DBC);
+ return ret;
+ }
+
+ //ret = SQLAllocStmt(CON_CONNECTION(_h), &CON_RESULT(_h));
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h),
&CON_RESULT(_h));
+ if (!SQL_SUCCEEDED(ret))
+ {
+ LOG(L_ERR, "Statement allocation error %d\n",
+ (int)(long)CON_CONNECTION(_h));
+ extract_error("SQLAllocStmt", CON_CONNECTION(_h),
SQL_HANDLE_DBC);
+ return ret;
+ }
+ }
+
ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
{
- LOG(L_ERR, "Return value: %d\n", ret);
- extract_error("SQLExecDirect", CON_CONNECTION(_h),
SQL_HANDLE_DBC);
+ LOG(L_ERR, "SQLExecDirect, rv=%d. Query= %s\n", ret, _s);
+ extract_error("SQLExecDirect", CON_RESULT(_h),
SQL_HANDLE_STMT);
+
+ //Close the cursor
+ SQLCloseCursor(CON_RESULT(_h));
+ SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
}
- return ret;
+ return ret;
}
/*
@@ -434,14 +484,14 @@
*(sql_buf + off) = '\0';
if (submit_query(_h, sql_buf) < 0)
{
- LOG(L_ERR, "db_query: Error while submitting query\n");
+ LOG(L_ERR, "unixodbc:db_query: Error while submitting
query\n");
return -2;
}
return store_result(_h, _r);
error:
- LOG(L_ERR, "db_query: Error in snprintf\n");
+ LOG(L_ERR, "unixodbc:db_query: Error in snprintf\n");
return -1;
}
@@ -600,9 +650,8 @@
ret = print_where(&CON_CONNECTION(_h), sql_buf + off,
SQL_BUF_LEN - off, _k, _o, _v, _n);
if (ret < 0) return -1;
off += ret;
-
- *(sql_buf + off) = '\0';
}
+ *(sql_buf + off) = '\0';
if (submit_query(_h, sql_buf) < 0)
{
Index: modules/unixodbc-SG/list.c
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/list.c,v
retrieving revision 1.5
diff -u -r1.5 list.c
--- modules/unixodbc-SG/list.c 10 Jan 2006 10:49:18 -0000 1.5
+++ modules/unixodbc-SG/list.c 6 Apr 2006 17:40:24 -0000
@@ -25,86 +25,70 @@
* History:
* --------
* 2005-12-01 initial commit (chgen)
+ * 2006-04-04 simplified link list (sgupta)
*/
#include "../../dprint.h"
#include "../../mem/mem.h"
#include "list.h"
-int insert(list l, int n, strn* value)
+int insert(list** start, list** link, int n, strn* value)
{
- int i;
- list ln;
-
- if(!l->next)
- {
- ln=(list)pkg_malloc(sizeof(element));
- if(!ln)
- {
- LOG(L_ERR,"ERROR:unixodbc:insert: No enought pkg
memory (1)\n");
- return -1;
- }
- ln->data=pkg_malloc(sizeof(strn)*n);
- if(!ln->data)
- {
- LOG(L_ERR,"ERROR:unixodbc:insert: No enought pkg
memory (2)\n");
- pkg_free(ln);
- return -1;
- }
- for(i=0; i<n; i++)
- strcpy(ln->data[i].s, value[i].s);
- /* link it */
- ln->next=NULL;
- ln->end=ln;
- l->next=ln;
- l->end=ln;
-
- return 0;
+ int i = 0;
+
+ if(!(*start)) {
+ *link = (list*)pkg_malloc(sizeof(list));
+ if(!(*link)) {
+ LOG(L_ERR,"ERROR:unixodbc:insert: Not enough pkg memory
(1)\n");
+ return -1;
+ }
+ (*link)->next = NULL;
+ (*link)->data = pkg_malloc(sizeof(strn)*n);
+ if(!(*link)->data) {
+ LOG(L_ERR,"ERROR:unixodbc:insert: Not enough pkg memory
(2)\n");
+ pkg_free(*link);
+ *link = NULL;
+ return -1;
+ }
+ for(i=0; i<n; i++)
+ strcpy((*link)->data[i].s, value[i].s);
+
+ *start = *link;
+ return 0;
}
else
- return insert(l->end, n, value);
-}
-
-void destroy(list l)
-{
- if(l->next)
- destroy(l->next);
- pkg_free(l->data);
- pkg_free(l);
-}
+ {
+ list* nlink;
+ nlink=(list*)pkg_malloc(sizeof(list));
+ if(!nlink) {
+ LOG(L_ERR,"ERROR:unixodbc:insert: Not enough pkg memory (3)\n");
+ return -1;
+ }
+ nlink->data = pkg_malloc(sizeof(strn)*n);
+ if(!nlink->data) {
+ LOG(L_ERR,"ERROR:unixodbc:insert: Not enough pkg memory (4)\n");
+ pkg_free(nlink);
+ return -1;
+ }
-strn* view(list l)
-{
- return l->data;
+ for(i=0; i<n; i++)
+ strcpy(nlink->data[i].s, value[i].s);
+
+ nlink->next = NULL;
+ (*link)->next = nlink;
+ *link = (*link)->next;
+
+ return 0;
+ }
}
-int create(list *l, int n, strn* value)
+void destroy(list *start)
{
- int i;
- if(*l)
- {
- LOG(L_WARN,"WARNING:unixodbc:create: List already
created\n");
- return 0;
- }
- *l=(list)pkg_malloc(sizeof(element));
- if(!*l)
- {
- LOG(L_ERR,"ERROR:unixodbc:create: No enought pkg memory
(1)\n");
- return -1;
- }
- (*l)->next=NULL;
- (*l)->end=*l;
- (*l)->data=pkg_malloc(sizeof(strn)*n);
- if(!(*l)->data)
- {
- LOG(L_ERR,"ERROR:unixodbc:create: No enought pkg memory
(2)\n");
- pkg_free(*l);
- *l = 0;
- return -1;
- }
- for(i=0; i<n; i++)
- strcpy((*l)->data[i].s, value[i].s);
-
- return 0;
+ while(start) {
+ list* temp = start;
+ start = start->next;
+ pkg_free(temp->data);
+ pkg_free(temp);
+ }
}
Index: modules/unixodbc-SG/list.h
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/list.h,v
retrieving revision 1.2
diff -u -r1.2 list.h
--- modules/unixodbc-SG/list.h 10 Jan 2006 10:49:18 -0000 1.2
+++ modules/unixodbc-SG/list.h 6 Apr 2006 17:40:24 -0000
@@ -25,6 +25,7 @@
* History:
* --------
* 2005-12-01 initial commit (chgen)
+ * 2006-04-04 simplified link list (sgupta)
*/
#ifndef _UNIXODBC_LIST_H_
@@ -34,23 +35,14 @@
#include <stdlib.h>
#include "my_con.h"
-typedef struct element
+typedef struct list
{
- struct element *next;
- struct element *end;
-
+ struct list *next;
strn *data;
-} element;
-
-typedef element* list;
-
-int insert(list l, int n, strn* value);
-
-void destroy(list l);
-
-strn* view(list l);
+} list;
-int create(list *l, int n, strn* value);
+int insert(list** start, list** link, int n, strn* value);
+void destroy(list* link);
#endif
Index: modules/unixodbc-SG/my_con.c
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/my_con.c,v
retrieving revision 1.4
diff -u -r1.4 my_con.c
--- modules/unixodbc-SG/my_con.c 1 Mar 2006 10:13:37 -0000 1.4
+++ modules/unixodbc-SG/my_con.c 6 Apr 2006 17:40:24 -0000
@@ -43,14 +43,14 @@
#define PWD_ATTR "PWD="
#define PWD_ATTR_LEN (sizeof(PWD_ATTR)-1)
-#define MAX_CONN_STR_LEN 2048
-static char *build_conn_str(struct db_id* id)
+char *build_conn_str(struct db_id* id, char *buf)
{
- static char buf[MAX_CONN_STR_LEN];
int len, ld, lu, lp;
char *p;
+ if (!buf) return 0;
+
ld = id->database?strlen(id->database):0;
lu = id->username?strlen(id->username):0;
lp = id->password?strlen(id->password):0;
@@ -104,7 +104,7 @@
SQLSMALLINT outstrlen;
int ret;
struct my_con* ptr;
- char *conn_str;
+ char conn_str[MAX_CONN_STR_LEN];
if (!id)
{
@@ -126,8 +126,7 @@
SQLSetEnvAttr(ptr->env, SQL_ATTR_ODBC_VERSION, (void *)
SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, ptr->env, &(ptr->dbc));
- conn_str = build_conn_str(id);
- if (conn_str==0) {
+ if (!build_conn_str(id, conn_str)) {
LOG(L_ERR, "ERROR:unixodbc:new_connection: failed to build "
"connection string\n");
return 0;
@@ -189,15 +188,11 @@
SQLSMALLINT len;
SQLRETURN ret;
- LOG(L_ERR,"ERROR:unixodbc: the driver reported the following
diagnostics "
- "whilst running %s\n",fn);
-
do
{
- ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
- sizeof(text), &len );
+ ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
sizeof(text), &len );
if (SQL_SUCCEEDED(ret))
- LOG(L_ERR,"\t%s:%ld:%ld:%s\n", state, (long)i,
(long)native, text);
+ LOG(L_ERR,"unixodbc:SQLGetDiagRec=%s:%ld:%ld:%s\n",
state, (long)i, (long)native, text);
}
while( ret == SQL_SUCCESS );
}
Index: modules/unixodbc-SG/my_con.h
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/my_con.h,v
retrieving revision 1.3
diff -u -r1.3 my_con.h
--- modules/unixodbc-SG/my_con.h 6 Mar 2006 09:00:40 -0000 1.3
+++ modules/unixodbc-SG/my_con.h 6 Apr 2006 17:40:24 -0000
@@ -66,6 +66,10 @@
#define CON_CONNECTION(db_con) (((struct my_con*)((db_con)->tail))->dbc)
#define CON_ROW(db_con) (((struct
my_con*)((db_con)->tail))->row)
#define CON_TIMESTAMP(db_con) (((struct
my_con*)((db_con)->tail))->timestamp)
+#define CON_ID(db_con) (((struct my_con*)((db_con)->tail))->id)
+#define CON_ENV(db_con) (((struct my_con*)((db_con)->tail))->env)
+#define MAX_CONN_STR_LEN 2048
+
/*
* Create a new connection structure,
@@ -76,7 +80,12 @@
/*
* Close the connection and release memory
*/
+
void free_connection(struct my_con* con);
void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type);
-#endif
/* MY_CON_H */
+
+char *build_conn_str(struct db_id* id, char *buf);
+
+
+#endif /* MY_CON_H */
Index: modules/unixodbc-SG/res.c
===================================================================
RCS file: /cvsroot/openser/sip-server/modules/unixodbc/res.c,v
retrieving revision 1.3
diff -u -r1.3 res.c
--- modules/unixodbc-SG/res.c 1 Mar 2006 10:13:37 -0000 1.3
+++ modules/unixodbc-SG/res.c 6 Apr 2006 17:40:24 -0000
@@ -25,6 +25,7 @@
* History:
* --------
* 2005-12-01 initial commit (chgen)
+ * 2006-04-04 fixed memory leak in convert_rows (sgupta)
*/
#include "../../mem/mem.h"
@@ -46,28 +47,28 @@
if ((!_h) || (!_r))
{
- LOG(L_ERR, "get_columns: Invalid parameter\n");
+ LOG(L_ERR, "unixodbc:get_columns: Invalid parameter\n");
return -1;
}
SQLNumResultCols(CON_RESULT(_h), &n);
if (!n)
{
- LOG(L_ERR, "get_columns: No columns\n");
+ LOG(L_ERR, "unixodbc:get_columns: No columns\n");
return -2;
}
-
+
RES_NAMES(_r) = (db_key_t*)pkg_malloc(sizeof(db_key_t) * n);
if (!RES_NAMES(_r))
{
- LOG(L_ERR, "get_columns: No memory left\n");
+ LOG(L_ERR, "unixodbc:get_columns: No memory left\n");
return -3;
}
RES_TYPES(_r) = (db_type_t*)pkg_malloc(sizeof(db_type_t) * n);
if (!RES_TYPES(_r))
{
- LOG(L_ERR, "get_columns: No memory left\n");
+ LOG(L_ERR, "unixodbc:get_columns: No memory left\n");
pkg_free(RES_NAMES(_r));
return -4;
}
@@ -131,7 +132,7 @@
if (!_r)
{
- LOG(L_ERR, "free_rows: Invalid parameter value\n");
+ LOG(L_ERR, "unixodbc:free_rows: Invalid parameter value\n");
return -1;
}
@@ -148,93 +149,89 @@
*/
static inline int convert_rows(db_con_t* _h, db_res_t* _r)
{
- int row, i, ret;
+ int row_n = 0, i = 0, ret = 0;
SQLSMALLINT columns;
- list rows = NULL;
- list l;
+ list* rows = NULL;
+ list* rowstart = NULL;
if((!_h) || (!_r))
{
- LOG(L_ERR, "convert_rows: Invalid parameter\n");
+ LOG(L_ERR, "unixodbc:convert_rows: Invalid parameter\n");
return -1;
}
- row = 0;
SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
CON_ROW(_h) = (strn*)pkg_malloc( columns*sizeof(strn) );
if(!CON_ROW(_h))
{
- LOG(L_ERR, "convert_rows: No memory left\n");
+ LOG(L_ERR, "unixodbc:convert_rows: No memory left\n");
return -1;
}
while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h))))
{
- for(i=1; i <= columns; i++)
+ for(i=0; i < columns; i++)
{
SQLINTEGER indicator;
- ret = SQLGetData(CON_RESULT(_h), i, SQL_C_CHAR,
- (CON_ROW(_h)[i-1]).s, STRN_LEN, &indicator);
- if (SQL_SUCCEEDED(ret))
- {
- if (indicator == SQL_NULL_DATA)
strcpy((CON_ROW(_h)[i-1]).s, "NULL");
+ ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR,
+ (CON_ROW(_h)[i]).s, STRN_LEN, &indicator);
+ if (SQL_SUCCEEDED(ret)) {
+ if (indicator == SQL_NULL_DATA)
strcpy((CON_ROW(_h)[i]).s, "NULL");
}
- else
- {
- LOG(L_ERR, "Error in SQLGetData\n");
+ else {
+ LOG(L_ERR, "unixodbc:convert_rows: Error in
SQLGetData\n");
}
}
- if(!row)
- {
- create(&rows, columns, CON_ROW(_h));
+
+ if (insert(&rowstart, &rows, columns, CON_ROW(_h)) < 0) {
+ LOG(L_ERR, "unixodbc:convertrows: insert failed\n");
+ pkg_free(CON_ROW(_h));
+ CON_ROW(_h) = NULL;
+ return -5;
}
- else
- {
- insert(rows, columns, CON_ROW(_h));
- }
- row++;
+
+ row_n++;
}
+ //free temporary CON_ROW(_h) data
+ pkg_free(CON_ROW(_h));
+ CON_ROW(_h) = NULL;
- RES_ROW_N(_r) = row;
- if (!row)
+ RES_ROW_N(_r) = row_n;
+ if (!row_n)
{
RES_ROWS(_r) = 0;
return 0;
}
- RES_ROWS(_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * row);
+ RES_ROWS(_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * row_n);
if (!RES_ROWS(_r))
{
- LOG(L_ERR, "convert_rows: No memory left\n");
+ LOG(L_ERR, "unixodbc:convert_rows: No memory left\n");
return -2;
}
i = 0;
- l = rows;
- while(l!=NULL)
+ rows = rowstart;
+ while(rows)
{
- CON_ROW(_h) = view(l);
- //for(j=0; j<columns; j++)
- //{
- //if(!strcmp(CON_ROW(_h)[j].s, "NULL"))
- // strcpy(CON_ROW(_h)[j].s, "");
- //}
+ CON_ROW(_h) = rows->data;
if (!CON_ROW(_h))
{
- LOG(L_ERR, "convert_rows: string null\n");
- RES_ROW_N(_r) = row;
+ LOG(L_ERR, "unixodbc:convert_rows: string null\n");
+ RES_ROW_N(_r) = row_n;
free_rows(_r);
return -3;
}
if (convert_row(_h, _r, &(RES_ROWS(_r)[i])) < 0)
{
- LOG(L_ERR, "convert_rows: Error while converting row
#%d\n", i);
+ LOG(L_ERR, "unixodbc:convert_rows: Error while
converting row #%d\n", i);
RES_ROW_N(_r) = i;
free_rows(_r);
return -4;
}
i++;
- l=l->next;
+ rows = rows->next;
}
- destroy(rows);
+
+ destroy(rowstart);
return 0;
}
cvs diff: Diffing modules/unixodbc-SG/doc
More information about the Devel
mailing list