From: drh Date: Sun, 14 Jan 2018 20:12:23 +0000 (+0000) Subject: Avoid excess stack usage when a VALUES clause with lots of rows occurs X-Git-Tag: version-3.22.0~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b058d05452079aee046a07e94a406b547c02b9f5;p=thirdparty%2Fsqlite.git Avoid excess stack usage when a VALUES clause with lots of rows occurs within a scalar expression. This fixes a problem discovered by OSSFuzz. FossilOrigin-Name: a4fa0581ba7cfd45fabe0198f55b3c2c8ee3ecfd2825aeed91116f44e77d760b --- diff --git a/manifest b/manifest index 296050499c..4a8b555cf8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sin\szipfile.c. -D 2018-01-13T23:28:33.571 +C Avoid\sexcess\sstack\susage\swhen\sa\sVALUES\sclause\swith\slots\sof\srows\soccurs\nwithin\sa\sscalar\sexpression.\s\sThis\sfixes\sa\sproblem\sdiscovered\sby\sOSSFuzz. +D 2018-01-14T20:12:23.878 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 38f84f301cbef443b2d269f67a74b8cc536469831f70df7c3e912acc04932cc2 @@ -438,7 +438,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6 F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720 F src/delete.c 20c8788451dc737a967c87ea53ad43544d617f5b57d32ccce8bd52a0daf9e89b -F src/expr.c ad6e7a9c34a4bab9d10cc857d647ae7ce370a633b5c0bfa71f1c29b81ae364b8 +F src/expr.c 46a7d73d5579feaee7a7274fac0efea0bbae71dd5b107a569501d89e0280c762 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331 F src/func.c bd528d5ed68ce5cbf78a762e3b735fa75009f7197ff07fab07fd771f35ebaa1b @@ -485,7 +485,7 @@ F src/printf.c 9506b4b96e59c0467047155f09015750cb2878aeda3d39e5610c1192ddc3c41c F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74 +F src/select.c bebe7cce45d899d2237c76bce059d525abf5b861f2fce92f6b53914a961c01ba F src/shell.c.in b87abffd0db09203ad8a133d56fe8f154ace5ec0a14197a153fb7d80b1438c01 F src/sqlite.h.in 9daf78e8f3cecc9ea0c3a82201f75bb74f789ecbfcda28d2e47fa80b3d956961 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1205,7 +1205,7 @@ F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3 F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394 F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3 -F test/selectG.test e8600e379589e85e9fefd2fe4d44a4cdd63f6982 +F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 @@ -1699,7 +1699,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f2d2a5df4f29b47212fd2411eae6545087b901a270655640c87ceb472e02a24c -R 8e0eefc806344b75dcd41a32589e33e5 +P 8f7a592f8c044d75b4615a95e27454100b10c2b26f4cafee97dec23343821130 +R 5b961a6038bd65800f58ecff32ab6963 U drh -Z 25a119edfc3f91c75d6d9bd6eb4524cb +Z 3c12035fed53223a4dcc5a3ae6914444 diff --git a/manifest.uuid b/manifest.uuid index 0bd548e74c..2a881ffea9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f7a592f8c044d75b4615a95e27454100b10c2b26f4cafee97dec23343821130 \ No newline at end of file +a4fa0581ba7cfd45fabe0198f55b3c2c8ee3ecfd2825aeed91116f44e77d760b \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 32cc4423fa..a63de5d9fc 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2764,7 +2764,6 @@ int sqlite3CodeSubselect( pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; - pSel->selFlags &= ~SF_MultiValue; if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } diff --git a/src/select.c b/src/select.c index 1a4b0a93af..c3cb4082fe 100644 --- a/src/select.c +++ b/src/select.c @@ -2184,9 +2184,14 @@ static int multiSelectOrderBy( ** on a VALUES clause. ** ** Because the Select object originates from a VALUES clause: -** (1) It has no LIMIT or OFFSET +** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1 ** (2) All terms are UNION ALL ** (3) There is no ORDER BY clause +** +** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES +** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))"). +** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case. +** Since the limit is exactly 1, we only need to evalutes the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ @@ -2194,13 +2199,13 @@ static int multiSelectValues( SelectDest *pDest /* What to do with query results */ ){ Select *pPrior; + Select *pRightmost = p; int nRow = 1; int rc = 0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); - assert( p->pLimit==0 ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); @@ -2212,7 +2217,7 @@ static int multiSelectValues( p->pPrior = 0; rc = sqlite3Select(pParse, p, pDest); p->pPrior = pPrior; - if( rc ) break; + if( rc || pRightmost->pLimit ) break; p->nSelectRow = nRow; p = p->pNext; } diff --git a/test/selectG.test b/test/selectG.test index 86d89b121b..fab4c4ed4d 100644 --- a/test/selectG.test +++ b/test/selectG.test @@ -36,4 +36,24 @@ do_test 100 { } } {100000 5000050000 50000.5 1} +# 2018-01-14. A 100K-entry VALUES clause within a scalar expression does +# not cause processor stack overflow. +# +do_test 110 { + set sql "SELECT (VALUES" + for {set i 1} {$i<100000} {incr i} { + append sql "($i)," + } + append sql "($i));" + db eval $sql +} {1} + +# Only the left-most term of a multi-valued VALUES within a scalar +# expression is evaluated. +# +do_test 120 { + set n [llength [split [db eval "explain $sql"] \n]] + expr {$n<10} +} {1} + finish_test