/ Check-in [a4fa0581]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Avoid excess stack usage when a VALUES clause with lots of rows occurs within a scalar expression. This fixes a problem discovered by OSSFuzz.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a4fa0581ba7cfd45fabe0198f55b3c2c8ee3ecfd2825aeed91116f44e77d760b
User & Date: drh 2018-01-14 20:12:23
Context
2018-01-15
14:32
Fix an error in the setDeviceCharacteristics() procedure for the (unsupported) QNX code in os_unix.c. check-in: 8151913a user: drh tags: trunk
2018-01-14
20:12
Avoid excess stack usage when a VALUES clause with lots of rows occurs within a scalar expression. This fixes a problem discovered by OSSFuzz. check-in: a4fa0581 user: drh tags: trunk
2018-01-13
23:28
Fix harmless compiler warnings in zipfile.c. check-in: 8f7a592f user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  2760   2760         if( pSel->pLimit ){
  2761   2761           sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
  2762   2762           pSel->pLimit->pLeft = pLimit;
  2763   2763         }else{
  2764   2764           pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
  2765   2765         }
  2766   2766         pSel->iLimit = 0;
  2767         -      pSel->selFlags &= ~SF_MultiValue;
  2768   2767         if( sqlite3Select(pParse, pSel, &dest) ){
  2769   2768           return 0;
  2770   2769         }
  2771   2770         rReg = dest.iSDParm;
  2772   2771         ExprSetVVAProperty(pExpr, EP_NoReduce);
  2773   2772         break;
  2774   2773       }

Changes to src/select.c.

  2180   2180   /*
  2181   2181   ** Handle the special case of a compound-select that originates from a
  2182   2182   ** VALUES clause.  By handling this as a special case, we avoid deep
  2183   2183   ** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
  2184   2184   ** on a VALUES clause.
  2185   2185   **
  2186   2186   ** Because the Select object originates from a VALUES clause:
  2187         -**   (1) It has no LIMIT or OFFSET
         2187  +**   (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1
  2188   2188   **   (2) All terms are UNION ALL
  2189   2189   **   (3) There is no ORDER BY clause
         2190  +**
         2191  +** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
         2192  +** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
         2193  +** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
         2194  +** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
  2190   2195   */
  2191   2196   static int multiSelectValues(
  2192   2197     Parse *pParse,        /* Parsing context */
  2193   2198     Select *p,            /* The right-most of SELECTs to be coded */
  2194   2199     SelectDest *pDest     /* What to do with query results */
  2195   2200   ){
  2196   2201     Select *pPrior;
         2202  +  Select *pRightmost = p;
  2197   2203     int nRow = 1;
  2198   2204     int rc = 0;
  2199   2205     assert( p->selFlags & SF_MultiValue );
  2200   2206     do{
  2201   2207       assert( p->selFlags & SF_Values );
  2202   2208       assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
  2203         -    assert( p->pLimit==0 );
  2204   2209       assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
  2205   2210       if( p->pPrior==0 ) break;
  2206   2211       assert( p->pPrior->pNext==p );
  2207   2212       p = p->pPrior;
  2208   2213       nRow++;
  2209   2214     }while(1);
  2210   2215     while( p ){
  2211   2216       pPrior = p->pPrior;
  2212   2217       p->pPrior = 0;
  2213   2218       rc = sqlite3Select(pParse, p, pDest);
  2214   2219       p->pPrior = pPrior;
  2215         -    if( rc ) break;
         2220  +    if( rc || pRightmost->pLimit ) break;
  2216   2221       p->nSelectRow = nRow;
  2217   2222       p = p->pNext;
  2218   2223     }
  2219   2224     return rc;
  2220   2225   }
  2221   2226   
  2222   2227   /*

Changes to test/selectG.test.

    32     32     append sql "($i);"
    33     33     set microsec [lindex [time {db eval $sql}] 0]
    34     34     db eval {
    35     35       SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1;
    36     36     }
    37     37   } {100000 5000050000 50000.5 1}
    38     38     
           39  +# 2018-01-14.  A 100K-entry VALUES clause within a scalar expression does
           40  +# not cause processor stack overflow.
           41  +#
           42  +do_test 110 {
           43  +  set sql "SELECT (VALUES"
           44  +  for {set i 1} {$i<100000} {incr i} {
           45  +    append sql "($i),"
           46  +  }
           47  +  append sql "($i));"
           48  +  db eval $sql
           49  +} {1}
           50  +
           51  +# Only the left-most term of a multi-valued VALUES within a scalar
           52  +# expression is evaluated.
           53  +#
           54  +do_test 120 {
           55  +  set n [llength [split [db eval "explain $sql"] \n]]
           56  +  expr {$n<10}
           57  +} {1}
           58  +
    39     59   finish_test