From: drh Date: Thu, 16 May 2019 01:22:21 +0000 (+0000) Subject: Make sure the OP_Concat opcode always correctly zero-terminates a UTF16 X-Git-Tag: version-3.29.0~96 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=df82afc04efbf269f3d4663cec04147421310f56;p=thirdparty%2Fsqlite.git Make sure the OP_Concat opcode always correctly zero-terminates a UTF16 string, even if the input strings are ill-formed. This is a followup to check-in [3a16ddf91f0c9c516a7] that fixes a case the previous check-in missed. Also add assert()s to prove correct zero termination. FossilOrigin-Name: d612fb7873cf59dfda18cabe45f674c37aa78a4587de3378b1840c99465a0269 --- diff --git a/manifest b/manifest index d7144649d4..39ca99b218 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\scount-of-view\soptimization\sso\sthat\sit\sis\s(correctly)\sdisabled\sfor\na\squery\sthat\sincludes\sa\sWHERE\sclause\sor\sa\sGROUP\sBY\sclause. -D 2019-05-15T18:42:15.232 +C Make\ssure\sthe\sOP_Concat\sopcode\salways\scorrectly\szero-terminates\sa\sUTF16\nstring,\seven\sif\sthe\sinput\sstrings\sare\sill-formed.\s\sThis\sis\sa\sfollowup\sto\ncheck-in\s[3a16ddf91f0c9c516a7]\sthat\sfixes\sa\scase\sthe\sprevious\scheck-in\smissed.\nAlso\sadd\sassert()s\sto\sprove\scorrect\szero\stermination. +D 2019-05-16T01:22:21.954 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -593,13 +593,13 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 4c0669e042b4e50a08a9e5fd14cecc76e5f877efa288533dccddb6fe98f4d6b5 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf -F src/vdbe.c d14841dc77e5b0cbd5cb857dee026f17b07a9d1ab147c1c2c9557227be6a52c9 +F src/vdbe.c 27fe1628d39aa7d71645d6a26f70066bd0e17cd74d010bad3bf73879efbe216a F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17 F src/vdbeapi.c f9161e5c77f512fbb80091ce8af621d19c9556bda5e734cffaac1198407400da F src/vdbeaux.c d444f4a3ff9c571965329a186701a57fe445e4c3f4c42f87402aca75386ba358 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 -F src/vdbemem.c b76b42ac9d6a36fc55a0797929fc94cc33e1334eea2792f5ee1eef868ce13320 +F src/vdbemem.c 14618670d96151efdcc0e0f0dd44a7a1acf94e065701159921e42ef19077b7d1 F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47 F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3 @@ -1825,7 +1825,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 adebffc18e6165672947a6bda5ca23ea7723cca7ab8da4feb81fca8f83e4fcaf -R b7271620cbaccc77f5dc0740795c22dc +P 05897ca48a40c6771ff83ba8ecc3a5c60dafddf58651c222dd8cf89b9fc7b077 +R c1522be20733136f28ced9b4722a52aa U drh -Z c38fee2bcfbeb4ee3d8baed90d28d7e4 +Z 5f545ffa57cd66d95ff033345f2b408a diff --git a/manifest.uuid b/manifest.uuid index eab2a2b2b9..8551903f4e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -05897ca48a40c6771ff83ba8ecc3a5c60dafddf58651c222dd8cf89b9fc7b077 \ No newline at end of file +d612fb7873cf59dfda18cabe45f674c37aa78a4587de3378b1840c99465a0269 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index c5452c5a89..78d46ebb7a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1501,7 +1501,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ + if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); @@ -1515,6 +1515,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ pIn1->flags = flags1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; + pOut->z[nByte+2] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; diff --git a/src/vdbemem.c b/src/vdbemem.c index 34b7c1f840..8d39351fe7 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -118,7 +118,10 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ #ifdef SQLITE_DEBUG /* -** Check that string value of pMem agrees with its integer or real value. +** Validity checks on pMem. pMem holds a string. +** +** (1) Check that string value of pMem agrees with its integer or real value. +** (2) Check that the string is correctly zero terminated ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. @@ -136,11 +139,22 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** ** This routine is for use inside of assert() statements only. */ -int sqlite3VdbeMemConsistentDualRep(Mem *p){ +int sqlite3VdbeMemValidStrRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; + if( p->flags & MEM_Term ){ + /* Insure that the string is properly zero-terminated. Pay particular + ** attention to the case where p->n is odd */ + if( p->z==p->zMalloc && p->szMalloc>0 ){ + assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); + assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); + } + assert( p->z[p->n]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); + } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; vdbeMemRenderNum(sizeof(zBuf), zBuf, p); z = p->z; @@ -1221,7 +1235,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; @@ -1244,7 +1258,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){