Search code examples
cpostgresqllibpq

Memory is not freed when connection to database is closed (C, postgres - libpq)


If you create a program with just the following two lines:

PGconn *conn = PQconnectdb("user=dbtest password=dbtest dbname=testdb host=localhost port=5432");
PQfinish(conn);

And run it through valgrind like so:

valgrind --leak-check=full --show-leak-kinds=all ./program

You see this:

==25388== Memcheck, a memory error detector
==25388== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25388== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==25388== Command: ./program
==25388== 
==25388== 
==25388== HEAP SUMMARY:
==25388==     in use at exit: 109 bytes in 2 blocks
==25388==   total heap usage: 6,948 allocs, 6,946 frees, 666,147 bytes allocated
==25388== 
==25388== 13 bytes in 1 blocks are still reachable in loss record 1 of 2
==25388==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25388==    by 0x4CB0635: CRYPTO_strdup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1)
==25388==    by 0x4BD8AFB: BIO_meth_new (in /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1)
==25388==    by 0x488BE8B: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x488D19C: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x487507F: PQconnectPoll (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x4875E3E: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x4878CD7: PQconnectdb (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x109158: main (in /workspace/test/src/program)
==25388== 
==25388== 96 bytes in 1 blocks are still reachable in loss record 2 of 2
==25388==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25388==    by 0x4CA70E8: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1)
==25388==    by 0x4BD8ADF: BIO_meth_new (in /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1)
==25388==    by 0x488BE8B: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x488D19C: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x487507F: PQconnectPoll (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x4875E3E: ??? (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x4878CD7: PQconnectdb (in /usr/lib/x86_64-linux-gnu/libpq.so.5.11)
==25388==    by 0x109158: main (in /workspace/test/src/program)
==25388== 
==25388== LEAK SUMMARY:
==25388==    definitely lost: 0 bytes in 0 blocks
==25388==    indirectly lost: 0 bytes in 0 blocks
==25388==      possibly lost: 0 bytes in 0 blocks
==25388==    still reachable: 109 bytes in 2 blocks
==25388==         suppressed: 0 bytes in 0 blocks
==25388== 
==25388== For counts of detected and suppressed errors, rerun with: -v
==25388== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

I noticed that opening and closing more connections doesn't seem to affect the amount of bytes lost or still reachable.

I'm not very familiar with C, so I have to ask:

How come there's bytes still reachable? I would expect everything to be deallocated when I close the connection to the database.


Solution

  • Those allocations were performed during the initialisation of libcrypto, which is used by the postgresql client in order to communicate with the server via SSL/TLS. That initialisation is only done once; it doesn't matter how many connections you open. (However, if the connections use different cyphers, there may be additional initialisations.)

    Libcrypto does provide interfaces which can be used to free storage allocated during initialisation. These are documented in the OpenSSL documentation. So you could try adding them to your code. But, honestly, it really doesn't matter except to make the valgrind report clearer.