SQLite Forum

App using SQlite C API faces segmentation fault

App using SQlite C API faces segmentation fault

(1) By Raymi (Raymi_C) on 2020-08-21 11:37:32 [link] [source]


I've an application writing log data to a SQLite3 database. Randomly, reason why I'm not able to reproduce the issue when needed, I'm facing app crash with segmentation fault. I succeeded to generate a SEGV dump which shows the following 2 traces.

I posting this as I'm trying to figure out what is the root cause for weeks but still struggling to solve.

1) sqlite3ExprListDup Trace

ip 0x7fff797b5b5d: _sigtramp+0x1d ip 0x7fff787b11d7: sqlite3ExprListDup+0x127 ip 0x7fff787b5e62: sqlite3SelectDup+0x132 ip 0x7fff787848af: selectExpander+0x4df ip 0x7fff787842f1: sqlite3WalkSelect+0x31 ip 0x7fff7885a87a: sqlite3SelectPrep+0x8a ip 0x7fff7877a7be: sqlite3Select+0x28e ip 0x7fff7874e28a: yy_reduce+0x10ca ip 0x7fff7874b658: sqlite3RunParser+0x218 ip 0x7fff78749d0a: sqlite3LockAndPrepare+0x48a ip 0x7fff787d61e7: sqlite3_prepare_v2+0xf7 ip 0x10ac75422: Connector::sqlite3Driver::executeDQL(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+0x82

2) sqlite3WhereBegin Trace

ip 0x7fff69eb5b5d: _sigtramp+0x1d ip 0x7fff68e8b804: sqlite3WhereBegin+0x1424 ip 0x7fff68e7da0f: sqlite3Select+0x34df ip 0x7fff68f6010f: multiSelectOrderBy+0xcef ip 0x7fff68e7d24e: sqlite3Select+0x2d1e ip 0x7fff68e7caaa: sqlite3Select+0x257a ip 0x7fff68e4e28a: yy_reduce+0x10ca ip 0x7fff68e4b658: sqlite3RunParser+0x218 ip 0x7fff68e49d0a: sqlite3LockAndPrepare+0x48a ip 0x7fff68ed61e7: sqlite3_prepare_v2+0xf7 ip 0x100996432: Connector::sqlite3Driver::executeDQL(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+0x82

The first trace occurs on INSERT statements into table that contains 6 columns. I found on the Web similar cases (Firefox) resulting from a bug prior to SQlite version 3.18.x and that was corrected as from this version. The second trace occurs on SELECT statement from the same table.

The environment is C++11 on MacOSX with sqlite-3.22.0 C API.

The log database is a one table structure.

Table DDL

CREATE TABLE IF NOT EXISTS log (uuid TEXT NOT NULL sourcename TEXT NOT NULL, sourceipaddress TEXT NOT NULL, stimestamp TEXT NOT NULL, qtimestamp TEXT NOT NULL, severity INTEGER NOT NULL, content TEXT NOT NULL); CREATE INDEX IF NOT EXISTS idx_uuid ON log (uuid); CREATE INDEX IF NOT EXISTS idx_stimestamp ON log (stimestamp); CREATE INDEX IF NOT EXISTS idx_qtimestamp ON log (qtimestamp); CREATE INDEX IF NOT EXISTS idx_severity ON log (severity);

When inserting data into the log table, the app executes INSERT statements by lot (50 rows) using a wrapper and ensures TRANSACTION BEGIN and COMMIT/ROLLBACK.

Application source code extract

[public] const bool Connector::open(const std::string& dbName, sqlite3 *dbConnection) { int connStatus = sqlite3_open("log.db", &dbConnection); if (connStatus == SQLITE_OK) { return true; ... //Wrapper maintains the connection to the SQLite database } else { return false; } } [public] const bool Connector::startTransac() { ... } [public] const bool Connector::commitTransac() { ... } [public] const bool Connector::rollbackTransac() { ... } [public] const int Connector::executeDQL(const std::string& queryStmt) { if (queryStmt.find("SELECT ") >= 0) { sqlite3_stmt *statement = nullptr; int sqLiteResult = sqlite3_prepare_v2(dbConnection, queryStmt.c_str(), -1, &statement, NULL); if (sqLiteResult == SQLITE_OK) { sqLiteResult = sqlite3_step(statement); sqLiteResult = sqlite3_finalize(statement); } return sqLiteResult; } else { return this->executeDML(queryStmt); } } [public] const int Connector::executeDML(const std::string& queryStmt) { char *errorMsg = 0; int sqLiteResult = sqlite3_exec(dbConnection, queryStmt.c_str(), nullptr, nullptr, &_errorMessage); if (sqLiteResult == SQLITE_OK) { sqLiteResult = sqlite3_changes(dbConnection); } return sqLiteResult }

The application is multi-threaded with mutex lockers but the connector class is a singleton not allowing concurrent calls.

Any help or suggestion to solve my issue would so much appreciated.

(2) By Larry Brasfield (LarryBrasfield) on 2020-08-21 15:28:59 in reply to 1 [link] [source]

Please see this post about heap corruption. The problem you report is much more likely due to that than random operation of the SQLite library. Given an intact heap, the library is remarkably deterministic.

(3) By Raymi (Raymi_C) on 2020-08-25 07:44:26 in reply to 2 [link] [source]

Ok, will try with XCode Instruments to check if there is a heap misuse.


(4) By Stephan Beal (stephan) on 2020-08-25 08:52:53 in reply to 1 [link] [source]

A sidebar unrelated to the question but related to the demonstrated code:

if (queryStmt.find("SELECT ") >= 0) ...

That's a very fragile way to check for whether a statement is capable of fetching data, for various reasons. Much more robust and generic is:

  • Prepare the query, regardless of what type you think it is based on string-sniffing.
  • Use sqlite3_column_count() to get the query's result column count: if it's 0, the statement is non-fetching (INSERT, UPDATE, etc.), else it is a SELECT, a SELECT-like pragma (if there are any such pragmas), or some such hypothetical construct.
  • Step the cursor one time. That will execute an INSERT/UPDATE/etc. the same as it will a SELECT, but it will return SQLITE_DONE instead of SQLITE_ROW.

The notable functional difference there from your current code is that sqlite3_exec() will compile and run all of the statements in the given string, whereas prepare/step will only handle the first statement (noting that the final argument to the step family of functions can be used to get the next position in the SQL so that the caller can loop over the string to handle each statement it includes).

(5) By Raymi (Raymi_C) on 2020-08-30 07:57:02 in reply to 4 [link] [source]

I fully agree with you, this should certainly be improved but in this case app is only performing SELECT and INSERT.

However, I gonna take into account your recommendation as I was not aware of the difference.

Many thanks

(6) By Keith Medcalf (kmedcalf) on 2020-08-30 09:03:34 in reply to 5 [source]