New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 665292 link

Starred by 1 user

Issue metadata

Status: Verified
Owner:
ex-Googler
Closed: Jan 2017
EstimatedDays: ----
NextAction: ----
OS: Linux
Pri: 1
Type: Bug



Sign in to add a comment

Hang in sqlite3_prepare_v2_fuzzer

Project Member Reported by ClusterFuzz, Nov 15 2016

Issue description

Owner: sh...@chromium.org
Status: Assigned (was: Untriaged)
shess@ could you please look into this.please feel free to re-assigned back if needed. thanks in advance !
Labels: Test-Predator-Wrong-CLs
Project Member

Comment 3 by sheriffbot@chromium.org, Nov 22 2016

Labels: -Restrict-View-EditIssue
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

Comment 4 by sh...@chromium.org, Jan 19 2017

Status: Started (was: Assigned)
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...

Comment 5 by sh...@chromium.org, 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.

Comment 6 by sh...@chromium.org, 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.
Project Member

Comment 7 by bugdroid1@chromium.org, 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

Project Member

Comment 8 by ClusterFuzz, 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.
Project Member

Comment 9 by ClusterFuzz, Jan 21 2017

Labels: ClusterFuzz-Verified
Status: Verified (was: Started)
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