Opening database in invalid location causes memory leak

I am using qt 4.5.3 to access the sqlite database, like this :

class db : private boost::noncopyable
{
 public:
  db( QString file ) : filename( file ),
                       realdb( NULL ),
                       theConnectionEstablished( false )
  {
  }
  ~db()
  {
    if ( NULL != realdb.get() )
    {
      realdb.reset( NULL );
    }
    if ( theConnectionEstablished )
    {
      QSqlDatabase::removeDatabase( "ConnName" );
    }
  }

  void open()
  {
    realdb.reset( new QSqlDatabase( QSqlDatabase::addDatabase( "QSQLITE", "ConnName" ) ) );
    theConnectionEstablished = true;

    // open the db
    realdb->setDatabaseName( filename );
    if ( ! realdb->open() )
    {
        const QSqlError dbError = realdb->lastError();
        const QString errorDesc = "Error opening the database : " + filename +
                                  "\nDatabase error : " + dbError.databaseText() +
                                  "\nDatabase driver error : " + dbError.driverText();

        // DatabaseError is a class type which accepts the std::string for logging purposes
        throw DatabaseError( errorDesc.toStdString() );
    }
  }

  const QString filename;
  std::auto_ptr<QSqlDatabase> realdb;
  bool theConnectionEstablished;
};

Now if I try to test this case like this (I am using cxxtest) :

void test_failed_connection()
{
  db obj( "/" );
  TS_ASSERT_THROWS( obj.open(), DatabaseError );
}

I get a memory leak reported by valgrind :

<error>
  <unique>0x5b</unique>
  <tid>1</tid>
  <kind>Leak_DefinitelyLost</kind>
  <what>986 (384 direct, 602 indirect) bytes in 1 blocks are definitely lost in loss record 23 of 23</what>
  <leakedbytes>986</leakedbytes>
  <leakedblocks>1</leakedblocks>
  <stack>
    <frame>
      <ip>0x4006D3E</ip>
      <obj>/opt/valgrind341/lib/valgrind/x86-linux/vgpreload_memcheck.so</obj>
      <fn>malloc</fn>
      <dir>/home/slawomir/valgrind-3.4.1/build/valgrind-3.4.1/coregrind/m_replacemalloc</dir>
      <file>vg_replace_malloc.c</file>
      <line>207</line>
    </frame>
    <frame>
      <ip>0x67FADC4</ip>
      <obj>/usr/lib/libsqlite3.so.0.8.6</obj>
      <fn>sqlite3_malloc</fn>
    </frame>
    <frame>
      <ip>0x67FAF13</ip>
      <obj>/usr/lib/libsqlite3.so.0.8.6</obj>
    </frame>
    <frame>
      <ip>0x6816DA3</ip>
      <obj>/usr/lib/libsqlite3.so.0.8.6</obj>
    </frame>
    <frame>
      <ip>0x68175FD</ip>
      <obj>/usr/lib/libsqlite3.so.0.8.6</obj>
      <fn>sqlite3_open16</fn>
    </frame>
    <frame>
      <ip>0x40DDEF9</ip>
      <obj>/usr/lib/qt4/plugins/sqldrivers/libqsqlite.so</obj>
    </frame>
    <frame>
      <ip>0x7F34AE0</ip>
      <obj>/usr/lib/libQtSql.so.4.5.2</obj>
      <fn>QSqlDatabase::open()</fn>
    </frame>
    </frame>
  </stack>
</error>

Does anyone know how to fix this leak?

Answers


Had a browse through the Qt and sqlite sources ... interesting.

Reading the manual for sqlite3_open16(), http://www.sqlite.org/c3ref/open.html, one finds the following quote:

Whether or not an error occurs when it is opened, resources associated with the database connection handle should be released by passing it to sqlite3_close() when it is no longer required.

QSQLiteDriver::close() seems to be calling that, http://qt.gitorious.org/qt/qt/blobs/4.7/src/sql/drivers/sqlite/qsql_sqlite.cpp, only in case of the open having been successful. SQLite's documentation might indicate that sqlite3_close() should be called either case.

On the other hand, http://www.sqlite.org/c3ref/close.html claims to be a no-op if NULL is passed for a handle (which would be if the open failed). A look into the SQLite sourcecode (DIY - I don't know a web source browser interface for it) confirms that, it just returns if called with NULL.

Well - now for the nitty-gritty fun of the issue...

Naively, one assumes that a failure of sqlite3_open*() would imply a NULL db handle. But according to SQLite's sources, read openDatabase() in main.c, that's not true - the call can fail but still return you a non-NULL db handle.

Qt looks like it assumes a failure to open the DB connection implies receiving a NULL db handle. But that's not what SQLite does. The documentation could be clearer, though.

Try adding that close into QSQLiteDriver::open() and see if it fixes the leak. If so, file a bug with the Qt guys, and another one with the SQLite folks to have the documentation clarified ;-)


Need Your Help

.GPS program code shows no error but 'unfortunately application stopped ' message coming on emulator . Please help me out

android gps android-manifest

GPS program code shows no error but unfortunately application stopped message coming on emulator.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.