Index: src/callback.c ================================================================== --- src/callback.c +++ src/callback.c @@ -100,11 +100,11 @@ p = sqlite3FindCollSeq(db, enc, zName, 0); } if( p && !p->xCmp && synthCollSeq(db, p) ){ p = 0; } - assert( !p || p->xCmp ); + assert( p==0 || (sqlite3ValidCollSeq(p) && p->xCmp!=0) ); if( p==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); } return p; } @@ -184,10 +184,35 @@ } } return pColl; } +#ifdef SQLITE_DEBUG +/* +** The following routine does sanity checking on a CollSeq object and +** returns 1 if everything looks ok and 0 if the CollSeq object appears +** to be corrupt. This routine is used only inside of assert() statements. +*/ +int sqlite3ValidCollSeq(const CollSeq *p){ + /* The CollSeq must be one of a triple and the zName field must + ** point to the first byte after that triple + */ + int n = (int)(p->zName - (char*)p)/sizeof(CollSeq); + if( n<=0 || n>3 ) return 0; + + /* Check for valid enc values */ + if( p->enc==SQLITE_UTF8 ) return 1; + if( p->enc==SQLITE_UTF16LE ) return 1; + if( p->enc==SQLITE_UTF16BE ) return 1; + if( p->enc==(SQLITE_UTF16LE|SQLITE_UTF16_ALIGNED) ) return 1; + if( p->enc==(SQLITE_UTF16BE|SQLITE_UTF16_ALIGNED) ) return 1; + + /* Otherwise, malformed */ + return 0; +} +#endif /* SQLITE_DEBUG */ + /* ** Parameter zName points to a UTF-8 encoded string nName bytes long. ** Return the CollSeq* pointer for the collation sequence named zName ** for the encoding 'enc' from the database 'db'. ** @@ -213,11 +238,14 @@ }else{ pColl = db->pDfltColl; } assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); - if( pColl ) pColl += enc-1; + if( pColl ){ + pColl += enc-1; + assert( sqlite3ValidCollSeq(pColl) ); + } return pColl; } /* During the search for the best function definition, this procedure ** is called to test how well the function passed as the first argument Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3451,10 +3451,13 @@ const char *sqlite3ErrName(int); #endif const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); +#if defined(SQLITE_DEBUG) +int sqlite3ValidCollSeq(const CollSeq*); +#endif CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -1052,10 +1052,11 @@ i = sqlite3Strlen30(zTemp); for(j=0; jnField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : "nil"; int n = sqlite3Strlen30(zColl); + assert( pColl==0 || sqlite3ValidCollSeq(pColl) ); if( n==6 && memcmp(zColl,"BINARY",6)==0 ){ zColl = "B"; n = 1; } if( i+n>nTemp-6 ){ @@ -3356,10 +3357,11 @@ const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl, u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ ){ + assert( sqlite3ValidCollSeq(pColl) ); if( pMem1->enc==pColl->enc ){ /* The strings are already in the correct encoding. Call the ** comparison function directly */ return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); }else{ @@ -3471,10 +3473,11 @@ ** compiled (this was not always the case). */ assert( !pColl || pColl->xCmp ); if( pColl ){ + assert( sqlite3ValidCollSeq(pColl) ); return vdbeCompareMemString(pMem1, pMem2, pColl, 0); } /* If a NULL pointer was passed as the collate function, fall through ** to the blob case and use memcmp(). */ }