Hi folks,
It seems that I can reliably segfault recent Pike 8.1 installs when using sprintf-style SQLite queries:
$ echo ' create table demo(a, b); insert into demo(a, b) values(1, "abc")' | sqlite3 demo.db
$ pike Pike v8.1 release 13 running Hilfe v3.5 [...] > Sql.Sql db = Sql.Sql("sqlite://demo.db"); > db->query("select * from demo"); (1) Result: ({ /* 1 element */ ([ /* 2 elements */ "a": "1", "b": "abc" ]) }) > db->query("select * from demo where a = :a", ([":a": 1 ])); (2) Result: ({ /* 1 element */ ([ /* 2 elements */ "a": "1", "b": "abc" ]) }) > db->query("select * from demo where a = %d", 1); Segmentation fault
This occurs on both macOS and Linux; on macOS, segfaults are observed when the SQLite module is linked against either MacPorts' SQLite 3 or the system wide dylib in /usr/lib.
Note that query() with a mapping argument doesn't segfault; furthermore, no such segfault occurs under Pike v8.0 release 702.
Please let me know whether this is reproducible (and/or whether more information is required).
Thanks, Marc
On Wed, Apr 29, 2020 at 5:13 AM Marc Simpson marc@0branch.com wrote:
Hi folks,
It seems that I can reliably segfault recent Pike 8.1 installs when using sprintf-style SQLite queries:
$ echo ' create table demo(a, b); insert into demo(a, b) values(1, "abc")' | sqlite3 demo.db $ pike Pike v8.1 release 13 running Hilfe v3.5 [...] > Sql.Sql db = Sql.Sql("sqlite://demo.db"); > db->query("select * from demo"); (1) Result: ({ /* 1 element */ ([ /* 2 elements */ "a": "1", "b": "abc" ]) }) > db->query("select * from demo where a = :a", ([":a": 1 ])); (2) Result: ({ /* 1 element */ ([ /* 2 elements */ "a": "1", "b": "abc" ]) }) > db->query("select * from demo where a = %d", 1); Segmentation fault
This occurs on both macOS and Linux; on macOS, segfaults are observed when the SQLite module is linked against either MacPorts' SQLite 3 or the system wide dylib in /usr/lib.
Note that query() with a mapping argument doesn't segfault; furthermore, no such segfault occurs under Pike v8.0 release 702.
Please let me know whether this is reproducible (and/or whether more information is required).
Reproduced on a very recent build of Pike. Can be done in a more self-contained way using an in-memory database:
Pike v8.1 release 13 running Hilfe v3.5 (Incremental Pike Frontend) Ok.
Sql.Sql db = Sql.Sql("sqlite://:memory:"); db->query("create table demo (a, b)");
(1) Result: 0
db->query("insert into demo values (1, 'abc')");
(2) Result: 0
db->query("select * from demo where a = :a", ([":a": 1]));
(3) Result: ({ /* 1 element */ ([ /* 2 elements */ "a": "1", "b": "abc" ]) })
db->query("select * from demo where a = %d", 1);
Segmentation fault
Will do some bisection.
ChrisA
On Tue, Apr 28, 2020 at 12:20 PM Chris Angelico rosuav@gmail.com wrote:
On Wed, Apr 29, 2020 at 5:13 AM Marc Simpson marc@0branch.com wrote:
[...]
It seems that I can reliably segfault recent Pike 8.1 installs when using sprintf-style SQLite queries: [...]
Reproduced on a very recent build of Pike. Can be done in a more self-contained way using an in-memory database:
Thanks Chris.
On Wed, Apr 29, 2020 at 5:25 AM Marc Simpson marc@0branch.com wrote:
On Tue, Apr 28, 2020 at 12:20 PM Chris Angelico rosuav@gmail.com wrote:
On Wed, Apr 29, 2020 at 5:13 AM Marc Simpson marc@0branch.com wrote:
[...]
It seems that I can reliably segfault recent Pike 8.1 installs when using sprintf-style SQLite queries: [...]
Reproduced on a very recent build of Pike. Can be done in a more self-contained way using an in-memory database:
Thanks Chris.
Okay, it's been a bit of digging, because behaviour changed at one point - sprintf-style parameters simply weren't accepted. But I've found the commit that introduced the segfault:
commit 6a37db6d0b7ff17c96ffa967c4f4c9064195fc70 Sql.Connection: always attempt to fetch any rows when converting a result to array.
Checking for fields is not sufficient, as some engines do not execute the query until the first row is fetched (SQLite for example). On queries that use sprintf bindings but return no rows (such as inserts), this resulted in the query never executing (and likely leaking the statement).
I'm not sure that that's actually the bug though - might just be where it's exposed. The crash results, I think, from calling fetch_row_array() for all rows, and then afterwards calling fetch_fields(); inside sqlite.cmod fetch_fields(), THIS->stmt has become a NULL pointer, resulting in the crash. (I believe that's happening in fetch_row(), which zeroes out the pointer once it gets SQLITE_DONE.)
That's as much as I can find.
ChrisA
So on SQLite you can fetch fields _neither_ before fetching the first row, _nor_ after fetching the last one? That's... special.
pike-devel@lists.lysator.liu.se