Thread: Leak repairs

Leak repairs

From
"Dave Page"
Date:
Hi Anoop,

I've spend a while (too long really!) tracking down the memory leaks
we've been seeing in the libpq driver. The code below is enough to see
the problems I've observed using perfmon monitoring the process's
private bytes value.

The attached patch fixes 2 leaks, each of which noticably reduce the
angle of the perfmon trace, however it's not quite flat yet, and my eyes
have gone blurry from looking! It seems to be leaking about 1Kb/per
SQLExecute/SQLFreeStmt (it was 4Kb when I started). It also removes an
unnecessary call to PQgetisnull that I noticed.

I haven't applied any of this to CVS - I'll leave that to you if you're
happy with it.

#include <windows.h>
#include <sqlext.h>
#include <stdio.h>

int main(void)
{
    HENV        hEnv = NULL;
    HDBC        hDBC = NULL;
    HSTMT       hStmt = NULL;
    UCHAR       szDSN[SQL_MAX_DSN_LENGTH] = "psqlodbc-libpq";
    UCHAR       szUID[64] = "postgres";
    UCHAR*      szPasswd = NULL;
    UCHAR       szSqlStr[] = "SELECT 1";
    RETCODE     retcode;
    long        loop = 0;

    SQLAllocEnv (&hEnv);
    SQLAllocConnect (hEnv, &hDBC);
    retcode = SQLConnect (hDBC, szDSN, SQL_NTS, szUID, SQL_NTS,
szPasswd, SQL_NTS);

    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
        while(loop < 100000)
        {
            retcode = SQLAllocStmt (hDBC, &hStmt);
            retcode = SQLPrepare (hStmt, szSqlStr, sizeof (szSqlStr));
            retcode = SQLExecute (hStmt);
            SQLFreeStmt (hStmt, SQL_DROP);
            loop++;
        }
        SQLDisconnect (hDBC);
    }

    SQLFreeConnect (hDBC);
    SQLFreeEnv (hEnv);

    return 0;
}

Regards, Dave.

Attachment

Re: Leak repairs

From
"Anoop Kumar"
Date:
Hi Dave,

I will certainly look into it today. Thanks for the exhaustive checking
of the code!

Regards

Anoop

-----Original Message-----
From: pgsql-odbc-owner@postgresql.org
[mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Dave Page
Sent: Friday, July 15, 2005 7:06 PM
To: pgsql-odbc@postgresql.org
Cc: Anoop Kumar
Subject: [ODBC] Leak repairs

Hi Anoop,

I've spend a while (too long really!) tracking down the memory leaks
we've been seeing in the libpq driver. The code below is enough to see
the problems I've observed using perfmon monitoring the process's
private bytes value.

The attached patch fixes 2 leaks, each of which noticably reduce the
angle of the perfmon trace, however it's not quite flat yet, and my eyes
have gone blurry from looking! It seems to be leaking about 1Kb/per
SQLExecute/SQLFreeStmt (it was 4Kb when I started). It also removes an
unnecessary call to PQgetisnull that I noticed.

I haven't applied any of this to CVS - I'll leave that to you if you're
happy with it.

#include <windows.h>
#include <sqlext.h>
#include <stdio.h>

int main(void)
{
    HENV        hEnv = NULL;
    HDBC        hDBC = NULL;
    HSTMT       hStmt = NULL;
    UCHAR       szDSN[SQL_MAX_DSN_LENGTH] = "psqlodbc-libpq";
    UCHAR       szUID[64] = "postgres";
    UCHAR*      szPasswd = NULL;
    UCHAR       szSqlStr[] = "SELECT 1";
    RETCODE     retcode;
    long        loop = 0;

    SQLAllocEnv (&hEnv);
    SQLAllocConnect (hEnv, &hDBC);
    retcode = SQLConnect (hDBC, szDSN, SQL_NTS, szUID, SQL_NTS,
szPasswd, SQL_NTS);

    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
        while(loop < 100000)
        {
            retcode = SQLAllocStmt (hDBC, &hStmt);
            retcode = SQLPrepare (hStmt, szSqlStr, sizeof (szSqlStr));
            retcode = SQLExecute (hStmt);
            SQLFreeStmt (hStmt, SQL_DROP);
            loop++;
        }
        SQLDisconnect (hDBC);
    }

    SQLFreeConnect (hDBC);
    SQLFreeEnv (hEnv);

    return 0;
}

Regards, Dave.

Re: Leak repairs

From
"Anoop Kumar"
Date:
Hi Dave,

I have tested the patch from you, and it does make the perfmon graph
less steep. I am applying the patch to CVS.

Regarding the call to PGgetisnull: My mistake! I forgot to remove it,
thanks for pointing it out.

Regards

Anoop


-----Original Message-----
From: pgsql-odbc-owner@postgresql.org
[mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Dave Page
Sent: Friday, July 15, 2005 7:06 PM
To: pgsql-odbc@postgresql.org
Cc: Anoop Kumar
Subject: [ODBC] Leak repairs

Hi Anoop,

I've spend a while (too long really!) tracking down the memory leaks
we've been seeing in the libpq driver. The code below is enough to see
the problems I've observed using perfmon monitoring the process's
private bytes value.

The attached patch fixes 2 leaks, each of which noticably reduce the
angle of the perfmon trace, however it's not quite flat yet, and my eyes
have gone blurry from looking! It seems to be leaking about 1Kb/per
SQLExecute/SQLFreeStmt (it was 4Kb when I started). It also removes an
unnecessary call to PQgetisnull that I noticed.

I haven't applied any of this to CVS - I'll leave that to you if you're
happy with it.

#include <windows.h>
#include <sqlext.h>
#include <stdio.h>

int main(void)
{
    HENV        hEnv = NULL;
    HDBC        hDBC = NULL;
    HSTMT       hStmt = NULL;
    UCHAR       szDSN[SQL_MAX_DSN_LENGTH] = "psqlodbc-libpq";
    UCHAR       szUID[64] = "postgres";
    UCHAR*      szPasswd = NULL;
    UCHAR       szSqlStr[] = "SELECT 1";
    RETCODE     retcode;
    long        loop = 0;

    SQLAllocEnv (&hEnv);
    SQLAllocConnect (hEnv, &hDBC);
    retcode = SQLConnect (hDBC, szDSN, SQL_NTS, szUID, SQL_NTS,
szPasswd, SQL_NTS);

    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
    {
        while(loop < 100000)
        {
            retcode = SQLAllocStmt (hDBC, &hStmt);
            retcode = SQLPrepare (hStmt, szSqlStr, sizeof (szSqlStr));
            retcode = SQLExecute (hStmt);
            SQLFreeStmt (hStmt, SQL_DROP);
            loop++;
        }
        SQLDisconnect (hDBC);
    }

    SQLFreeConnect (hDBC);
    SQLFreeEnv (hEnv);

    return 0;
}

Regards, Dave.

Re: Leak repairs

From
"Dave Page"
Date:

> -----Original Message-----
> From: Anoop Kumar [mailto:anoopk@pervasive-postgres.com]
> Sent: 19 July 2005 07:35
> To: Dave Page
> Cc: pgsql-odbc@postgresql.org
> Subject: RE: [ODBC] Leak repairs
>
> Hi Dave,
>
> I have tested the patch from you, and it does make the perfmon graph
> less steep. I am applying the patch to CVS.


Great, thanks. Any joy tracking down the last little bit?

> Regarding the call to PGgetisnull: My mistake! I forgot to remove it,
> thanks for pointing it out.

No problem.

I think we should put out a second snapshot sometime, as soon as the
rest of this memory leak is fixed, and the Excel problem is sorted. Any
progress on that one?

Also we need to expose the libpq SSL option to the user, probably on the
main connection dialogue, and obviously as a connection string option.
At the same time, the protocol version options can be removed. I can
probably look at that if you are pushed for time - let me know what you
prefer.

Finally, the threading problem. After discussion with Bruce Momjian and
Magnus Hagander, we think that the --enable-thread-safety configure
option should be used on Windows as well as other platforms as it does
do more than just enable critical sections around non-thread safe API
calls. I am (as time allows!) working on fixing PostgreSQL to allow
this.

Regards, Dave

Re: Leak repairs

From
Marko Ristola
Date:
Have you seen this one?

1121712844: 17186:  not freed: '0x404ef808|s1' (800 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x404f0c08|s1' (800 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x404fd008|s1' (3200 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x404fe008|s1' (3200 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x404ff008|s1' (3200 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x40500008|s1' (3200 bytes) from
'qresult.c:421'
1121712844: 17186:  not freed: '0x40501008|s1' (3200 bytes) from
'qresult.c:421'

Line 421 allocates a buffer into QResultClass.backend_tuples.

backend_tuples will be set into NULL in QR_Destructor() with
"self->backend_tuples = NULL". I suspect, that the memory leak.

Marko Ristola

Dave Page wrote:

>
>
>
>
>>-----Original Message-----
>>From: Anoop Kumar [mailto:anoopk@pervasive-postgres.com]
>>Sent: 19 July 2005 07:35
>>To: Dave Page
>>Cc: pgsql-odbc@postgresql.org
>>Subject: RE: [ODBC] Leak repairs
>>
>>Hi Dave,
>>
>>I have tested the patch from you, and it does make the perfmon graph
>>less steep. I am applying the patch to CVS.
>>
>>
>
>
>Great, thanks. Any joy tracking down the last little bit?
>
>
>
>>Regarding the call to PGgetisnull: My mistake! I forgot to remove it,
>>thanks for pointing it out.
>>
>>
>
>No problem.
>
>I think we should put out a second snapshot sometime, as soon as the
>rest of this memory leak is fixed, and the Excel problem is sorted. Any
>progress on that one?
>
>Also we need to expose the libpq SSL option to the user, probably on the
>main connection dialogue, and obviously as a connection string option.
>At the same time, the protocol version options can be removed. I can
>probably look at that if you are pushed for time - let me know what you
>prefer.
>
>Finally, the threading problem. After discussion with Bruce Momjian and
>Magnus Hagander, we think that the --enable-thread-safety configure
>option should be used on Windows as well as other platforms as it does
>do more than just enable critical sections around non-thread safe API
>calls. I am (as time allows!) working on fixing PostgreSQL to allow
>this.
>
>Regards, Dave
>
>---------------------------(end of broadcast)---------------------------
>TIP 1: if posting/reading through Usenet, please send an appropriate
>       subscribe-nomail command to majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly
>
>


Re: Leak repairs

From
"Dave Page"
Date:

> -----Original Message-----
> From: pgsql-odbc-owner@postgresql.org
> [mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Marko Ristola
> Sent: 19 July 2005 08:37
> Cc: Anoop Kumar; pgsql-odbc@postgresql.org
> Subject: Re: [ODBC] Leak repairs
>
>
> Have you seen this one?
>
> 1121712844: 17186:  not freed: '0x404ef808|s1' (800 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x404f0c08|s1' (800 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x404fd008|s1' (3200 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x404fe008|s1' (3200 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x404ff008|s1' (3200 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x40500008|s1' (3200 bytes) from
> 'qresult.c:421'
> 1121712844: 17186:  not freed: '0x40501008|s1' (3200 bytes) from
> 'qresult.c:421'
>
> Line 421 allocates a buffer into QResultClass.backend_tuples.
>
> backend_tuples will be set into NULL in QR_Destructor() with
> "self->backend_tuples = NULL". I suspect, that the memory leak.
>

Nicely spotted :-)

That would appear to be the last of them (at least for my simple testing
at the moment). I'll commit a patch shortly.

BTW, I assume you got that output from the VC++ debugger - care to share
how? I spent quite some time trying to persuade it to give me that and
didn't get anywhere :-(

Regards, Dave.

Re: Leak repairs

From
Marko Ristola
Date:

I experimented almost the hole monday with dmalloc library.
So that was not efficient. I wanted to see, wether there
is a tool, that can debug the psqlodbc library behind
UnixODBC under Linux.

I don't have any Windows development environment.
I could though install Mingw into Windows XP.

So, the dmalloc library is under Debian Linux as a package
and easy to install though.

Here is, how I did it:
test.c:
#include <dmalloc.h>
test.c linking: gcc needed option -ldmallocth (threaded version).

I modified psqlodbclibpq in the following way:
PGAPI_AllocEnv() function in environ.c:
dmalloc_debug_setup("debug=0x4f4ed03,log=liblogfile");

This activates the memory debugging. liblogfile is the file, where the
results go.

PGAPI_FreeEnv() in environ.c:
dmalloc_shutdown(); // before return of return SQL_SUCCESS

Actually this setup crashes within dlclose inside UnixODBC library.
But, the debugging information will get written into "liblogfile",
because the log will be written inside PGAPI_FreeEnv().

I did compile test.c and psqlodbclibpq with -g and without optimizations
to achieve a good debugging environment.

This was the code block within an active connect:

  for (i=0; i<5; i++)
    {
      if
(!CHECK(SQL_HANDLE_DBC,m_conn,SQLAllocHandle(SQL_HANDLE_STMT,m_conn,&m_stmt)))
        return 1;

      if (!CHECK(SQL_HANDLE_STMT,m_stmt,SQLExecDirect(m_stmt,(SQLCHAR*)
"SELECT * FROM TEST1 LIMIT 100", SQL_NTS)))
        return 1;

      if (!CHECK(SQL_HANDLE_DBC,m_conn,SQLFreeStmt(m_stmt,SQL_DROP)))
        return 1;
    }



Marko Ristola

Dave Page wrote:

>
>
>
>
>>-----Original Message-----
>>From: pgsql-odbc-owner@postgresql.org
>>[mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Marko Ristola
>>Sent: 19 July 2005 08:37
>>Cc: Anoop Kumar; pgsql-odbc@postgresql.org
>>Subject: Re: [ODBC] Leak repairs
>>
>>
>>Have you seen this one?
>>
>>1121712844: 17186:  not freed: '0x404ef808|s1' (800 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x404f0c08|s1' (800 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x404fd008|s1' (3200 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x404fe008|s1' (3200 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x404ff008|s1' (3200 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x40500008|s1' (3200 bytes) from
>>'qresult.c:421'
>>1121712844: 17186:  not freed: '0x40501008|s1' (3200 bytes) from
>>'qresult.c:421'
>>
>>Line 421 allocates a buffer into QResultClass.backend_tuples.
>>
>>backend_tuples will be set into NULL in QR_Destructor() with
>>"self->backend_tuples = NULL". I suspect, that the memory leak.
>>
>>
>>
>
>Nicely spotted :-)
>
>That would appear to be the last of them (at least for my simple testing
>at the moment). I'll commit a patch shortly.
>
>BTW, I assume you got that output from the VC++ debugger - care to share
>how? I spent quite some time trying to persuade it to give me that and
>didn't get anywhere :-(
>
>Regards, Dave.
>
>---------------------------(end of broadcast)---------------------------
>TIP 9: In versions below 8.0, the planner will ignore your desire to
>       choose an index scan if your joining column's datatypes do not
>       match
>
>


Re: Leak repairs

From
"Dave Page"
Date:

> -----Original Message-----
> From: pgsql-odbc-owner@postgresql.org
> [mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Dave Page
> Sent: 19 July 2005 10:50
> To: Marko Ristola
> Cc: Anoop Kumar; pgsql-odbc@postgresql.org
> Subject: Re: [ODBC] Leak repairs
>
>
> That would appear to be the last of them (at least for my
> simple testing
> at the moment). I'll commit a patch shortly.

The patch below has been committed. Oddly though, I was demonstrating
the memory leak to someone here and removed the fix to show what
shouldn't happen - the perfmon trace remained flat! Unless my previous
testing was flawed in someway, it now appears that I cannot reproduce
the remaining leak I saw. Oh well...

> BTW, I assume you got that output from the VC++ debugger -
> care to share
> how? I spent quite some time trying to persuade it to give me that and
> didn't get anywhere :-(

I saw your other email on that - thanks for the info.

Regards, Dave.

Index: qresult.c
===================================================================
RCS file: /usr/local/cvsroot/psqlodbc/psqlodbc/qresult.c,v
retrieving revision 1.50
diff -u -r1.50 qresult.c
--- qresult.c    15 Jul 2005 09:53:34 -0000    1.50
+++ qresult.c    19 Jul 2005 10:00:22 -0000
@@ -156,13 +156,17 @@
         TL_Destructor(self->manual_tuples);
         self->manual_tuples = NULL;
     }
-
+
     /*
      * If conn is defined, then we may have used "backend_tuples",
so in
      * case we need to, free it up.  Also, close the cursor.
      */
 #ifdef USE_LIBPQ
-    self->backend_tuples = NULL;
+    if (self->backend_tuples)
+    {
+        free(self->backend_tuples);
+        self->backend_tuples = NULL;
+     }
     if (conn && conn->pgconn && CC_is_in_trans(conn))
 #else
     if (conn && conn->sock && CC_is_in_trans(conn))

Re: Leak repairs

From
"Anoop Kumar"
Date:
Hi Dave,

I saw the patch just now and tested it. For me it works well and I am
getting a flat trace graph.

Regards

Anoop



-----Original Message-----
From: Dave Page [mailto:dpage@vale-housing.co.uk]
Sent: Tuesday, July 19, 2005 3:53 PM
To: Marko Ristola
Cc: Anoop Kumar; pgsql-odbc@postgresql.org
Subject: RE: [ODBC] Leak repairs



> -----Original Message-----
> From: pgsql-odbc-owner@postgresql.org
> [mailto:pgsql-odbc-owner@postgresql.org] On Behalf Of Dave Page
> Sent: 19 July 2005 10:50
> To: Marko Ristola
> Cc: Anoop Kumar; pgsql-odbc@postgresql.org
> Subject: Re: [ODBC] Leak repairs
>
>
> That would appear to be the last of them (at least for my
> simple testing
> at the moment). I'll commit a patch shortly.

The patch below has been committed. Oddly though, I was demonstrating
the memory leak to someone here and removed the fix to show what
shouldn't happen - the perfmon trace remained flat! Unless my previous
testing was flawed in someway, it now appears that I cannot reproduce
the remaining leak I saw. Oh well...

> BTW, I assume you got that output from the VC++ debugger -
> care to share
> how? I spent quite some time trying to persuade it to give me that and
> didn't get anywhere :-(

I saw your other email on that - thanks for the info.

Regards, Dave.

Index: qresult.c
===================================================================
RCS file: /usr/local/cvsroot/psqlodbc/psqlodbc/qresult.c,v
retrieving revision 1.50
diff -u -r1.50 qresult.c
--- qresult.c    15 Jul 2005 09:53:34 -0000    1.50
+++ qresult.c    19 Jul 2005 10:00:22 -0000
@@ -156,13 +156,17 @@
         TL_Destructor(self->manual_tuples);
         self->manual_tuples = NULL;
     }
-
+
     /*
      * If conn is defined, then we may have used "backend_tuples",
so in
      * case we need to, free it up.  Also, close the cursor.
      */
 #ifdef USE_LIBPQ
-    self->backend_tuples = NULL;
+    if (self->backend_tuples)
+    {
+        free(self->backend_tuples);
+        self->backend_tuples = NULL;
+     }
     if (conn && conn->pgconn && CC_is_in_trans(conn))
 #else
     if (conn && conn->sock && CC_is_in_trans(conn))