sqlite3_deserialize double memory freeing
(1) By Roger Binns (rogerbinns) on 2021-07-19 22:29:29 [link] [source]
I'm experiencing a double free in SQLite code on close when using sqlite3_deserialize. The C library complains: free(): double free detected in tcache 2 as does valgrind complain in the sqlite3_close.
Specifically I serialize the main db, and then deserialize it into the temp db. Full code is at https://gist.github.com/rogerbinns/d11994c1d85e36c341e20f25ec491f5e
Extract (leaving out error checking for clarity - error checking is in gist):
/* in memory db with default flags */ res = sqlite3_open_v2("", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); /* create a table so the database is not empty */ res = sqlite3_exec(db, "create table foo(x)", NULL, NULL, NULL); /* serialize */ serialized = sqlite3_serialize(db, "main", &serial_size, 0); /* copy the data */ datacopy = sqlite3_malloc64(serial_size); memcpy(datacopy, serialized, serial_size); /* free serialized (caller is responsible for freeing the returned value to avoid a memory leak) */ sqlite3_free(serialized); /* now load data into temp */ res = sqlite3_deserialize(db, "temp", datacopy, serial_size, serial_size, SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); sqlite3_close(db);
The sqlite3_deserialize() interface does not work for TEMP. That is not intentional. It should work. But TEMP is special and requires some special handling. And, as it turns out, I neglected to include any test cases that deserialize TEMP in any of the SQLite test suites. So it probably has never worked. I suspect that you are the first person to have tried to deserialized into TEMP.
(3) By Roger Binns (rogerbinns) on 2021-07-22 20:51:44 in reply to 2 [link] [source]
I was only doing that to avoid having to open another database, just to check that my serialize/deserialize wrapper works correctly! Now I create the content in temp and deserialize into main. (I also had to rename the table that got copied otherwise some queries claim that the copied table doesn't exist when it clearly does - it seemed like deserialize wasn't setting a schema has changed flag unless I did the spurious modification.)