0

I'm trying to write a C++ program that will communicate with different DB providers. Everything works fine now, however upon exiting I'm trying to close the connection and the disconnect command crashes. At the moment I'm testing with SQLite, so it probably belong to this specific one.

Do I have to close the connection to the SQLite upon program termination? I believe generally it is a good idea to release the resources the program is using, but what about this case? I mean in this case the SQLite DB file will be released back to the system when the program exits, so its not actually a loss.

Thank you.

[EDIT]

As requested I'm submitting the code that I use.

In DLL1 (database.h):

#ifndef DBMANAGER_DATABASE
#define DBMANAGER_DATABASE

class __declspec(dllexport) Database
{
public:
    Database();
    virtual ~Database();
    static void *operator new(size_t size);
    static void operator delete(void *ptr, size_t size);
};
#endif

In DLL1 (database.cpp)

#include <string>
#include "database.h"

Database::Database()
{
}

Database::~Database()
{
}

void *Database::operator new(std::size_t size)
{
    return ::operator new( size );
}

void Database::operator delete(void *ptr, std::size_t size)
{
    return ::operator delete( ptr );
}

In DLL2: (database_sqlite.h):

#ifndef DBMANAGER_SQLITE
#define DBMANAGER_SQLITE
class __declspec(dllexport) SQLiteDatabase : public Database
{
public:
    SQLiteDatabase();
    virtual ~SQLiteDatabase();
    virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
protected:
    void GetErrorMessage(int code, std::wstring &errorMsg);
private:
    sqlite3 *m_db;
};
#endif

In DLL2: (database_sqlite.cpp)

#ifdef WIN32
#include <windows.h>
#pragma execution_character_set("utf-8")
#endif
#include <vector>
#include <string>
#include <sqlext.h>
#include "sqlite3.h"
#include "database.h"
#include "database_sqlite.h"

SQLiteDatabase::SQLiteDatabase() : Database()
{
}

SQLiteDatabase::~SQLiteDatabase()
{
    sqlite3_close( m_db );
}

int SQLiteDatabase::Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg)
{
    int result = 0;
    std::wstring errorMessage;
    int res = sqlite3_open( selectedDSN, &m_db );
    if( res != SQLITE_OK )
    {
        // get error messages GetErrorMessage( res, errorMessage );
        errorMsg.push_back( errorMessage );
        result = 1;
    }
    else
    {
        res = sqlite3_exec( m_db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL );
        if( res != SQLITE_OK )
        {
            // get error message GetErrorMessage( res, errorMessage );
            errorMsg.push_back( errorMessage );
            result = 1;
        }
    }
    return result;
}

In DLL3: (dialogs.cpp)

#ifdef __GNUC__
#pragma implementation "dialogs.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#include <vector>
#include "sqlite3ext.h"
#include "database.h"
#include "database_sqlite.h"

#ifdef _WINDOWS

BOOL APIENTRY DllMain( HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
    lpReserved = lpReserved;
    hModule = hModule;
    int argc = 0;
    char **argv = NULL;
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
#endif

extern "C" __declspec(dllexport) Database *DatabaseProfile(Database *db)
{
    db = new SQLiteDatabase;
    return db;
}

In main application (test_app.cpp):

#include "stdafx.h"
#include "database.h"
#include <windows.h>
#include <stdio.h>

typedef Database *(__cdecl *MYFUNC)(Database *);

class A
{
public:
    A(Database *db)
    {
    m_db = NULL;
    HINSTANCE hInst = LoadLibrary( TEXT( "dialogs.dll" ) );
    MYFUNC func = (MYFUNC) GetProcAddress( hInst, "DatabaseProfile" );
    m_db = func( db );
    }
    ~A()
    {
    }
    Database *GetDatabase()
    {
        return m_db;
    }
private:
    Database *m_db;
};

int _tmain(int argc, _TCHAR* argv[])
{
    Database *db = NULL, *m_db;
    A *a = new A( db );
    m_db = a->GetDatabase();
    delete m_db;
    delete a;
    return 0;
}

[EDIT]

Running this code I am getting the crash executing "delete "m_db" line. SQLite is compiled in from source code.

Any idea?

Thank you.

Igor
  • 5,620
  • 11
  • 51
  • 103
  • It would be great to see the code that's causing the crash. – ForceBru Feb 11 '16 at 16:51
  • @ForceBru, Basically I have created an SQLite wrapper and put it inside the DLL. Then in another DLL I create an object of this class and pass it back to the main application. When the main application exits it is crashing trying to acquire a global lock inside SQLite. I can post some code later today after I get out of work. – Igor Feb 11 '16 at 16:55
  • Please show a [mcve]. – CL. Feb 11 '16 at 17:51
  • @CL., As I said, I will post the code later. But independently, do I have to close the connection or not? – Igor Feb 11 '16 at 18:32
  • You should. You have a double free or memory corruption, which should be fixed anyway. – CL. Feb 11 '16 at 21:54
  • @CL., code added. I skipped error handling and DLL loading as it is irrelevant to the issue. Thank you. – Igor Feb 14 '16 at 06:17
  • This is not a complete example. – CL. Feb 14 '16 at 07:29
  • @CL, What do you meanby "not complete example"? I can share the complete code if that's what you are asking, but it is to big to submit it here. I posted just relevant piece of the code. Please tell me what's best. Thank you. – Igor Feb 14 '16 at 14:47
  • I cannot compile and test your code. – CL. Feb 14 '16 at 14:48
  • @CL., but you can see if there is something wrong with it or even in project settings that needs to be changed. I'm compiling SQLite from source and my compiler is set to be C++. Do I have to explicitly change it to use C for SQLite? – Igor Feb 14 '16 at 14:53
  • It is likely that the problem is in the resource management of some other stuff (e.g., `MainFrame`). – CL. Feb 14 '16 at 14:55
  • @CL, so what's the best way to debug it? It something like this: I call Connect() function, get a connection to database - no errors and no problems. Then right after I close the window at which point I am getting a crash. – Igor Feb 14 '16 at 15:04
  • To debug this, create a *minimal* and *complete* example. – CL. Feb 14 '16 at 15:24
  • @CL, it looks like I hit the issue discussed here: http://stackoverflow.com/questions/17531558/crt-virtual-destructor, but I don't understand the response given. I am exporting the class and have overriden new/delete If I read the accepted answer correctly I should export only constructor and destructor and get rid of new/delete. But then my Database class won't be fully accessible outside the DLL. Can you please explain this – Igor Feb 15 '16 at 05:04
  • No, you should export the entire class. Anyway, can you reproduce the error with such a simple class? – CL. Feb 15 '16 at 08:04
  • @CL, yes, no need to create a derived. Just one class. Adding "virtual" makes it crash on exit. Also, I do have an overriden new/delete pair in Database. – Igor Feb 15 '16 at 15:53
  • So now you have a minimal and complete example? – CL. Feb 15 '16 at 16:09
  • @CL, yup, I do. You want me to upload it somewhere? – Igor Feb 15 '16 at 16:56
  • If it's minimal, you can put it into the question. – CL. Feb 15 '16 at 17:24
  • @CL, done. I made changes to the code I originally posted. As you can see I allocate memory inside DLL for the Database object and delete the memory when the main frame is destroyed. It is the same thing as on the link I referenced, but there the OP exports only constructor and destructor. – Igor Feb 15 '16 at 22:50
  • This is not a complete example; the `MainFrame` class is missing. Do you get the same problem when you just move the code of these two `MainFrame` function directly into `main`? – CL. Feb 16 '16 at 07:34
  • @CL, this is Windows/GUI application. So no main(). If you have a basic Windows application just use the main frame of it. I don't have it at hand unfortunately but I guess I can create a basic WinMain... – Igor Feb 16 '16 at 11:44
  • @CL, I put in some simple main application which makes the code crash on the "delete m_db" line. However I'm not sure that this is the same as in my application. In my Windows application the pointer address is the same but running this code I see that the m_db address is changed. So I'm not sure if fixing this will help me, but lets try. I am willing to experiment. Thank you. – Igor Feb 17 '16 at 05:41
  • The class member `m_db` is never initialized because of the local variable with the same name in `A`'s constructor. – CL. Feb 17 '16 at 07:36
  • @CL, Sorry for the delay. I made a simple console application which is crashing. Should I create a new thread? Also how much code is allowed to be posted here on SO? – Igor Feb 23 '16 at 04:17
  • It's the same problem, so just edit the question. Please note that SO is not a forum but a Q&A site, and that the edit history is available anyway; remove those "edit" markers and bring the question into a form as if it had been perfect from the beginning. – CL. Feb 23 '16 at 06:39
  • @CL, Code, the question and the tags are updated. See anything wrong? These lines are just cut'n'paste from the solution. Thank you. P.S.: If needed I can update it with the solution properties. – Igor Feb 24 '16 at 05:32
  • Does the application have a static dependency on DLL1? – CL. Feb 24 '16 at 20:51
  • @CL, If you mean main application - yes, it does. It has a Database pointer and so links to the lib file produced. – Igor Feb 24 '16 at 20:59
  • You must not use `dllexport` in a header that is actually used by another module. In that case, this should to be replaced with `dllimport`. – CL. Feb 25 '16 at 20:29
  • @CL, Not sure what you mean. The DLL1 Database class should be exported, otherwise it will not be visible to another class/main application. Can you clarify a little? – Igor Feb 26 '16 at 03:51
  • But the class must not be exported *from the main application*. – CL. Feb 26 '16 at 07:48
  • @CL, and it's not. Main application just uses it - that's all. Nowhere there there is a code "__declspec(dllexport) Database". It is only inside DLL1. Main application, DLL2 and DLL3 are only using this class - main application has a pointer to it, DLL2 has a child of it and DLL3 uses it from polymorphism POV. It is b being exported only in one place - DLL1. – Igor Feb 26 '16 at 14:46
  • The header file (which is *textually* included) says `dllexport`, even inside the main app. – CL. Feb 26 '16 at 14:49
  • @CL, ok, so create some macro and depending on it being defined use either dllexport or dllimport, right? I can try that and see if that will fix it... – Igor Feb 26 '16 at 15:24

0 Answers0