sqlite3_step after sqlite3_finalize: what is the expected behavior?
(1.1) By Alain (McMartin) on 2021-09-18 13:24:01 edited from 1.0 [source]
Up until check-in f7ab01f2, the following program would work:
#include <sqlite3.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
int main()
{
sqlite3 *db;
sqlite3_stmt *stmt;
int rc;
rc = sqlite3_open(":memory:", &db);
assert(rc == SQLITE_OK);
const char* sql = "SELECT 0 WHERE 0;";
rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, 0);
assert(rc == SQLITE_OK);
rc = sqlite3_finalize(stmt);
assert(rc == SQLITE_OK);
rc = sqlite3_step(stmt);
assert(rc == SQLITE_MISUSE);
rc = sqlite3_close(db);
assert(rc == SQLITE_OK);
printf("All good!\n");
return 0;
}
Calling sqlite3_step
on a finalized statement returned SQLITE_MISUSE
, which seems sensible and matches the (current) documentation of sqlite3_step
:
** [SQLITE_MISUSE] means that the this routine was called inappropriately.
** Perhaps it was called on a [prepared statement] that has
** already been [sqlite3_finalize | finalized]
Then, in check-in 52a12e47, the default lookaside configuration was changed and that program crashes with a segmentation fault, which matches the (current) documentation of sqlite3_finalize
:
** It is a grievous error for the application to try to use
** a prepared statement after it has been finalized. Any use of a prepared
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
So what is the expected behavior?
If the documentation of sqlite3_finalize
holds the truth, then the documentation of sqlite3_step
deserves an update to avoid confusion.
Also, is there any case where using a prepared statement that has been finalized doesn't crash?
(2.1) By Larry Brasfield (larrybr) on 2021-09-18 13:39:31 edited from 2.0 in reply to 1.0 [link] [source]
If the documentation of sqlite3_finalize holds the truth ...
It does. The phrase "can result in undefined behavior" includes the possibility of behavior not recognized as grievous. A better phrasing might be "results in undefined behavior" (which includes not seg-faulting), but that invites the same perplexity you have shared.
then the documentation of sqlite3_step deserves an update to avoid confusion.
I am not seeing it that way yet. What specific part of the doc you quoted for the SQLITE_MISUSE return do you believe to be false or confusing? If that return is seen, it means what is claimed. That logical (if-then) relation does not imply its converse, (which would be "If this routine is called inappropriately, then SQLITE_MISUSE will be returned.") Among the possible outcomes of an inappropriate call is a seg-fault, as is documented explicitly and is implicitly included in "undefined behavior".
At present, I am disinclined to further elaborate that documentation merely to make explicit such a result of elementary logic. Doing so would be in the same category as adding, to every positive assertion, something like: "This does not mean P, Q, R ... (without logical end)."
(3) By Alain (McMartin) on 2021-09-18 14:40:28 in reply to 2.1 [link] [source]
Thanks a lot for the very quick answer!
After re-reading these pieces of documentation, I agree that they don't contradict each other, nor the previous or current behavior.
I guess I need to come up with a way of keeping track of which prepared statements have been finalized, in my own code.