vesontio
vesontio

Reputation: 381

Possible memory leak in the shared library of sqlite3

I've coded 2 simple functions.

The first one establishes connection with my database and enable foreign key support:

int hmd_db_connect (sqlite3 *db) {
    char *sql;
    sqlite3_stmt *stmt;

    if (sqlite3_open_v2(HMD_DB_PATH, &db,
            SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE,
            NULL) != SQLITE_OK) {
        hmd_log_err("Failed to connect to database [Path: %s]: %s.",
                HMD_DB_PATH, sqlite3_errmsg(db));
        return -1;
    }

    sql = hmd_make_str("PRAGMA foreign_keys = ON");

    if (sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL) != SQLITE_OK) {
        hmd_log_err("Failed to prepare SQL [%s]: %s.",
                sql, sqlite3_errmsg(db));
        hmd_db_disconnect(db);
        free(sql);
        return -1;
    }

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        hmd_log_err("Failed to enable foreign key support: %s.",
                sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        hmd_db_disconnect(db);
        free(sql);
        return -1;
    }

    sqlite3_finalize(stmt);
    free(sql);
    return 0;
}

The second closes the connection:

int hmd_db_disconnect (sqlite3 *db) {
    if (sqlite3_close(db) != SQLITE_OK) {
        hmd_log_err("Failed to disconnect from database [Path: %s]: %s.",
                HMD_DB_PATH, sqlite3_errmsg(db));
        return -1;
    }
    return 0;
}

Then in my main function, I call these 2 functions:

_info("Connecting to database.\n");
hmd_db_connect(db);
_info("Database connected.\n");

_info("Disconnecting from database.\n");
hmd_db_disconnect(db);
_info("Database disconnected.\n");

The program doesn't show any error message. But when I run it with valgrind, it shows possible memory leak:

==11079== LEAK SUMMARY:
==11079==    definitely lost: 0 bytes in 0 blocks
==11079==    indirectly lost: 0 bytes in 0 blocks
==11079==      possibly lost: 57,768 bytes in 47 blocks
==11079==    still reachable: 0 bytes in 0 blocks
==11079==         suppressed: 0 bytes in 0 blocks
==11079== 
==11079== For counts of detected and suppressed errors, rerun with: -v
==11079== ERROR SUMMARY: 47 errors from 47 contexts (suppressed: 6 from 6)

I've checked the log of valgrind, all of the errors are detected inside the shared library of sqlite3, and I don't see any unfree'd variable.

Any idea please ?

Upvotes: 0

Views: 2241

Answers (1)

Artem Razin
Artem Razin

Reputation: 1286

I think hmd_db_connect is incorrect. It should return sqlite3*, but it takes sqlite3* instead of sqlite3**. You just lose sqlite3* returned by sqlite3_open_v2, imagine:

sqlite3* db = NULL;
hmd_db_connect(db);

db still will be NULL even if hmd_db_connect successfully opened the database.

I've modified the code:

int hmd_db_connect(sqlite3 **db) {
    char *sql;
    sqlite3_stmt *stmt;

    if (sqlite3_open_v2(HMD_DB_PATH, db,
        SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE,
        NULL) != SQLITE_OK) {
        hmd_log_err("Failed to connect to database [Path: %s]: %s.",
            HMD_DB_PATH, sqlite3_errmsg(*db));
        return -1;
    }

    sql = hmd_make_str("PRAGMA foreign_keys = ON");

    if (sqlite3_prepare_v2(*db, sql, strlen(sql), &stmt, NULL) != SQLITE_OK) {
        hmd_log_err("Failed to prepare SQL [%s]: %s.",
            sql, sqlite3_errmsg(*db));
        hmd_db_disconnect(*db);
        free(sql);
        return -1;
    }

    if (sqlite3_step(stmt) != SQLITE_DONE) {
        hmd_log_err("Failed to enable foreign key support: %s.",
            sqlite3_errmsg(*db));
        sqlite3_finalize(stmt);
        hmd_db_disconnect(*db);
        free(sql);
        return -1;
    }

    sqlite3_finalize(stmt);
    free(sql);
    return 0;
}

and it seems no leaks now.

Upvotes: 2

Related Questions