Access violation on sqlite3_mutex_enter(). Why?

2

I'm using sqlite-amalgamation-3080500 within a Python3/C module.

My python module creates some tables and then returns the sqlite3's handle to the python environment using PyCapsule.

So, in a second module, I try to create more tables using this same sqlite3's handle. But my program is breaking. I get an "access violation error" into sqlite3_mutex_enter() - which has been called by sqlite3_prepare_v2().

First-chance exception at 0x00000000 in python.exe: 0xC0000005: Access violation executing location 0x00000000. Unhandled exception at 0x7531C9F1 in python.exe: 0xC0000005: Access violation executing location 0x00000000.

Is it really thread-safe? I think I can do it this way. I've already did it in the past, but I was using XCode on Mac. Now I'm trying to do the same on MSVC 2013.

Bellow is my code to run queries:

bool register_run(register_db_t *pReg, const char *query)
{
    int ret, len;
    sqlite3_stmt *stmt;
    const char *err;

    stmt = NULL;

    len = (int)strlen(query);

    ret = sqlite3_prepare_v2(pReg->pDb, query, len, &stmt, NULL);

    if (ret != SQLITE_OK) {

        err = sqlite3_errmsg(pReg->pDb);

        fprintf(stderr, "sqlite3_prepare_v2 error: %s\n%s\n",
                err, query);

        return false;
    }


    ret = register_run_stmt(pReg, query, stmt);

    sqlite3_finalize(stmt);

    return ret;
}

And this is how I export the handle to use it in my 2nd C/module:

// Register's getattro
static PyObject* Register_getattro(RegisterObject *self, PyObject *name)
{
    // ...
    } else if (PyUnicode_CompareWithASCIIString(name, "handle") == 0) {
        register_db_t *handle = self->db;

        return PyCapsule_New(handle, NULL, NULL);
    }

    return PyObject_GenericGetAttr((PyObject *)self, name);
}

This is the python code gluing pieces:

import registermodule, loggermodule

reg = registermodule.Register("mydata.db")
loggermodule.set_register(reg.handle)

And how I use the the handle on my second module:

static PyObject* loggerm_set_register(PyObject *self, PyObject *args)
{
    register_db_t *pReg;
    PyObject *capsule;

    if (!PyArg_ParseTuple(args, "O:set_register", &capsule)) {
        return NULL;
    }

    if (!PyCapsule_CheckExact(capsule)) {
        PyErr_SetString(PyExc_ValueError,
            "The object isn't a valid pointer.");
        return NULL;
    }

    pReg = PyCapsule_GetPointer(capsule, NULL);

    if (!logger_set_register(pReg)) {
        PyErr_SetString(PyExc_SystemError,
            "Could not set the pointer as register.");
        return NULL;
    }

    Py_RETURN_NONE;
}

And finally the routine that is breaking:

bool logger_set_register(register_db_t *pReg)
{
    char *query = "CREATE TABLE IF NOT EXISTS tab_logger ("
                "date       NUMERIC,"
                "level      TEXT,"
                "file       TEXT,"
                "function   TEXT,"
                "line       INTEGER,"
                "message    TEXT)";
    g_pReg = pReg;

    return register_run(g_pReg, query);
}

And the sqlite3's routine that is breaking all:

SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
  if( p ){
    sqlite3GlobalConfig.mutex.xMutexEnter(p);
  }
}

Sorry about lots of snippets, but I've no clue about the problem.

Thanks in advance.

python
c
python-3.x
sqlite
asked on Stack Overflow Jun 16, 2014 by Daniel Koch

2 Answers

2

I don't know why, but globals are not the same between Python C modules on Windows. It wasn't on Mac OS, in despite of my previous experience doing so.

In Windows, python modules are DLLs, so they don't share the same global stack.

I've discovered that sqlite3Config.mutex was NULL to my second Python C module. It was causing the Access Violation error. But sqlite3Config.mutex is a global variable, this thing should be started by the previous module.

Now, knowing this point, I solved the problem calling this function:

sqlite3_initialize();

And all is working properly!

answered on Stack Overflow Jun 17, 2014 by Daniel Koch
0

Not sure your problem is directly related to sqlite3_initialize(); Because sqlite3_initialize(); is automatically called, at least once, during sqlite3_open_v2.

I suggest to dig in the lack of the option SQLITE_OPEN_FULLMUTEX during sqlite3_open_v2. Recommendation set this option always. Penalty of using Mutex is extremely low especially in view of all the overhead Python add. Negligeable in single thread and mandatory (nearly) in multithread. I don't even understand why it stay an option. should be there always So better safe than sorry. I don't know of real downside to use. SQLite is "lite"

BTW it is legit for sqlite3Config.mutex to be NULL. This should used only be used by SQLite that check this condition, search sqlite3.c for "

sqlite3_mutex_enter(db->mutex);

" to understand what I mean.

answered on Stack Overflow Jan 6, 2021 by Gordon88

User contributions licensed under CC BY-SA 3.0