Hang in sqlite3_prepare_v2_fuzzer |
|||||
Issue descriptionDetailed report: https://cluster-fuzz.appspot.com/testcase?key=5382080981893120 Fuzzer: libfuzzer_sqlite3_prepare_v2_fuzzer Job Type: libfuzzer_chrome_asan Platform Id: linux Crash Type: Hang Crash Address: Crash State: sqlite3_prepare_v2_fuzzer Regressed: https://cluster-fuzz.appspot.com/revisions?job=libfuzzer_chrome_asan&range=395675:395769 Minimized Testcase (0.17 Kb): https://cluster-fuzz.appspot.com/download/AMIfv94Bh9UBl_ViPjGmDRpHn3JdXr4ZfjODSM3If6UAZ7EUm7vaf-J5rqroIvxknaoYQW4ETBrzy-htRhsRpeLY6jsl1nVmOB8hyAlyiR0aoEv2kjGcFlEHj_QXhmD0x3BfiVOAFswM8KwLxjzLHiHu848EiBElsw?testcase_id=5382080981893120 Issue filed automatically. See https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/reproducing.md for more information.
,
Nov 16 2016
,
Nov 22 2016
Removing EditIssue view restrictions from ClusterFuzz filed bugs. If you believe that this issue should still be restricted, please reapply the label. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Jan 19 2017
15s on my Linux box!
I'm still trying to figure out the mechanism, here. A cleaner repro is:
SELECT printf(" %.*G",515|| 01888888,9)``WHERE``|``|``|``|``|``<``|``|``|``|``*``|``|``|``||``|``|``|``||``|``|``|``<``|``|``|``|``||``|``|``|``|``;
Here's what I _think_ is happening:
1) 515||01888888 converts those integers to a string, then back to a large integer to be the precision for %.*G. It's ~5GB, so will be maxed by SQLITE_PRINTF_PRECISION_LIMIT=128000000 . If I set that to 1280 the test completes in 1ms. If I replace the concatenated precision with a literal, it gets 3x faster.
2) Everything after the printf's closing ) acts as some sort of leverage. Without any of that, it completes quickly. Removing |`` groups trims the time.
The `` are interpreted as tokens, which aren't strings. "SELECT `this`;" gives "no such column: this". "" also delimits a token, but with special treatment (SELECT "this"; gives the result "this"). In most cases, `` causes an error. The narrowest statement I can find is:
SELECT "s"``WHERE ``|``<``;
which gives a single row containing "s". If I replace "s" with 1, no results.
EXPLAIN SELECT "s"``WHERE ``|``<``;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 5 0 00 Start at 5
1 Ge 2 4 1 51 if r[2]>=r[1] goto 4
2 String8 0 3 0 s 00 r[3]='s'
3 ResultRow 3 1 0 00 output=r[3]
4 Halt 0 0 0 00
5 String8 0 4 0 s 00 r[4]='s'
6 String8 0 5 0 s 00 r[5]='s'
7 BitOr 5 4 1 00 r[1]=r[5]|r[4]
8 String8 0 2 0 s 00 r[2]='s'
9 Goto 0 1 0 00
If I read this right, it's doing a bit-wise or of "s" with "s", then comparing it to "s", and returning a result >=."s"|"s" is 0, 0<"s", so the result is "s".
OK, so now the EXPLAIN on the original makes more sense. It has bits like this:
5 String8 0 13 0 %.*G 00 r[13]=' %.*G'
6 Integer 515 16 0 00 r[16]=515
7 Integer 1888888 17 0 00 r[17]=1888888
8 Concat 17 16 14 00 r[14]=r[16]+r[17]
9 Integer 9 15 0 00 r[15]=9
10 Function0 7 13 12 printf(-1) 03 r[12]=func(r[13..15])
which I believe means "convert these two ints to strings, concat, printf with a giant buffer, then return a relatively-small string". Then this runs again inline (duplicates the code, not the result), following by:
17 BitOr 17 12 11 00 r[11]=r[17]|r[12]
Which takes "9"|"9" -> 9. The concat and multiply cases are basically the same, and the < case is similar to above. So now my repro is:
SELECT printf(" %.*G",515||01888888,9)``WHERE``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``|``<``
which is 32 `` on the | side, plus one more on the RHS.
But I still don't know why this even hits...
,
Jan 19 2017
Aha!
Logically, here's what's happening:
SELECT printf("%.*G",515||01888888,9) AS a WHERE a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a|a<a;
You can omit the AS, and the `` acts as a delimiter. So the empty token is apparently valid.
,
Jan 19 2017
I was wrong about "relatively-small string" earlier - fuzzer reports rss of ~450MB, which is 35x SQLITE_PRINTF_PRECISION_LIMIT, so probably it's actually just giant strings, and the trimming is coming at the end. WRT fixes ... printf() is defined as SQLITE_FUNC_CONSTANT, which means constant inputs lead to deterministic outputs. So in theory the optimizer should be able to calculate things once and use the result multiple times. I'm not entirely sure why this isn't happening in this case. I checked SQLite trunk, and it hasn't changed. It also doesn't lift the expression if it's something simple like "9"||"9", so maybe the optimizer just doesn't handle that. [I'll ping drh about that.] Currently we have SQLITE_PRINTF_PRECISION_LIMIT=128000000 . Each 0 I drop from that drops this test by an order of magnitude. I can't think of any legitimate reason to have that much precision, and I can't think of any reasonable argument for why SQLite will work differently with 1280000. About all I can think of is how it works in OOM cases, which I think simply leads to an OOM in our system. So I think that's the way to go.
,
Jan 20 2017
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/9b1279144e1a29b56992dd6e5bf233f5889cc583 commit 9b1279144e1a29b56992dd6e5bf233f5889cc583 Author: shess <shess@chromium.org> Date: Fri Jan 20 17:09:57 2017 [sql] Lower SQLITE_PRINTF_PRECISION_LIMIT for fuzzer. Real-world usage should never involve precisions above maybe 100. The previous limit of 128M makes it very easy to blow out memory when fuzzing, and since OOM is already fatal, I'm not sure that such a large limit provides any productive coverage beyond something more reasonable. BUG= 665292 R=mmoroz@chromium.org Review-Url: https://codereview.chromium.org/2641123004 Cr-Commit-Position: refs/heads/master@{#445080} [modify] https://crrev.com/9b1279144e1a29b56992dd6e5bf233f5889cc583/third_party/sqlite/BUILD.gn
,
Jan 21 2017
ClusterFuzz has detected this issue as fixed in range 445079:445086. Detailed report: https://cluster-fuzz.appspot.com/testcase?key=5382080981893120 Fuzzer: libfuzzer_sqlite3_prepare_v2_fuzzer Job Type: libfuzzer_chrome_asan Platform Id: linux Crash Type: Timeout (exceeds 25 secs) Crash Address: Crash State: sqlite3_prepare_v2_fuzzer Sanitizer: address (ASAN) Regressed: https://cluster-fuzz.appspot.com/revisions?job=libfuzzer_chrome_asan&range=395675:395769 Fixed: https://cluster-fuzz.appspot.com/revisions?job=libfuzzer_chrome_asan&range=445079:445086 Minimized Testcase (0.17 Kb): https://cluster-fuzz.appspot.com/download/AMIfv94Bh9UBl_ViPjGmDRpHn3JdXr4ZfjODSM3If6UAZ7EUm7vaf-J5rqroIvxknaoYQW4ETBrzy-htRhsRpeLY6jsl1nVmOB8hyAlyiR0aoEv2kjGcFlEHj_QXhmD0x3BfiVOAFswM8KwLxjzLHiHu848EiBElsw?testcase_id=5382080981893120 See https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/reproducing.md for more information. If you suspect that the result above is incorrect, try re-doing that job on the test case report page.
,
Jan 21 2017
ClusterFuzz testcase 5382080981893120 is verified as fixed, so closing issue. If this is incorrect, please add ClusterFuzz-Wrong label and re-open the issue. |
|||||
►
Sign in to add a comment |
|||||
Comment 1 by mmohammad@chromium.org
, Nov 16 2016Status: Assigned (was: Untriaged)