SQLite

View Ticket
Login
2016-04-07
21:22
Prevent the in-memory journal read cursor from entering an inconsistent state when it reads the last few bytes out of the journal file. Fix for ticket [7f7f8026eda38]. (check-in: c232b99e user: drh tags: branch-3.12.0)
21:14 Fixed ticket [7f7f8026]: Segfault following heavy SAVEPOINT usage plus 3 other changes (artifact: c9b6953f user: drh)
21:14
Add test cases for ticket [7f7f8026eda387d544]. (check-in: 87aa9357 user: drh tags: trunk)
21:07 Ticket [7f7f8026] Segfault following heavy SAVEPOINT usage status still Open with 3 other changes (artifact: 26ac4c61 user: drh)
20:54 Ticket [7f7f8026]: 6 changes (artifact: 282da264 user: drh)
18:42
Prevent the in-memory journal read cursor from entering an inconsistent state when it reads the last few bytes out of the journal file. Fix for ticket [7f7f8026eda38]. (check-in: c4b9c611 user: drh tags: trunk)
18:31 New ticket [7f7f8026] Segfault following heavy SAVEPOINT usage. (artifact: af77e034 user: drh)

Ticket Hash: 7f7f8026eda387d544b85742558a6393f7ab7bbc
Title: Segfault following heavy SAVEPOINT usage
Status: Fixed Type: Code_Defect
Severity: Critical Priority: Immediate
Subsystem: Unknown Resolution: Fixed
Last Modified: 2016-04-07 21:14:43
Version Found In: 3.12.0
User Comments:
drh added on 2016-04-07 18:31:34:

A defect in the in-memory journal logic can leave the read cursor for the in-memory journal in an inconsistent state, which can result in a segfault. No simple test case is (currently) available for this problem. One must make heavy use of the SAVEPOINT operation to make it happen.

This problem was discovered by Django testing.


drh added on 2016-04-07 20:54:57:

The problem only comes up when the size of a savepoint journal (which is a multiple of 1028 bytes) is an exact multiple of the in-memory journal buffer size, which defaults to 1016 bytes on 64-bit machines and 1020 bytes on 32-bit machines. And even then, you have to do just the right sequence of SAVEPOINT operations to get the cursor to be reused.

The following scripts will segfault 64-bit builds of SQLite 3.12.0:

PRAGMA page_size=1024;
BEGIN;
CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<250)
INSERT INTO t1(x,y) SELECT x*10, printf('%04d%.800c',x,'*') FROM c;
SAVEPOINT one;
  SELECT count(*) FROM t1;
  WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<250)
  INSERT INTO t1(x,y) SELECT x*10+1, printf('%04d%.800c',x,'*') FROM c;
ROLLBACK TO one;
  SELECT count(*) FROM t1;
  SAVEPOINT twoB;
    WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<10)
    INSERT INTO t1(x,y) SELECT x*10+2, printf('%04d%.800c',x,'*') FROM c;
  ROLLBACK TO twoB;
RELEASE one;
COMMIT;

For 32-bit builds, change the two "250" constants to "251".


drh added on 2016-04-07 21:07:21:

For some builds (depending on compile-time settings) it might be necessary to add

PRAGMA temp_store=MEMORY;

to the top of the test script in the previous comment.