Fix an integer overflow in fts3 causing a usan error.
Backports https://sqlite.org/src/info/e256f85289a78e62
FossilOrigin-Name: e256f85289a78e629acdf83e5bf1f8df2a0ffb3d559738eb9e49db6c228dc8c0
(cherry picked from commit fc7f31742de0fea66610ac3211b40e27a467c923)
Bug: 1072736
Change-Id: I939c7290e16125109d34ba50fcb2e2591932cc45
diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c
index 01e4906..97bbc0a 100644
--- a/amalgamation/sqlite3.c
+++ b/amalgamation/sqlite3.c
@@ -1167,7 +1167,7 @@
*/
#define SQLITE_VERSION "3.31.1"
#define SQLITE_VERSION_NUMBER 3031001
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt1"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -164677,6 +164677,7 @@
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -165410,6 +165411,22 @@
}
/*
+** Buffer z contains a positive integer value encoded as utf-8 text.
+** Decode this value and store it in *pnOut, returning the number of bytes
+** consumed. If an overflow error occurs return a negative value.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){
+ u64 iVal = 0;
+ int i;
+ for(i=0; z[i]>='0' && z[i]<='9'; i++){
+ iVal = iVal*10 + (z[i] - '0');
+ if( iVal>0x7FFFFFFF ) return -1;
+ }
+ *pnOut = (int)iVal;
+ return i;
+}
+
+/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
** sets *pp to point to the byte immediately following the last byte of
@@ -165424,19 +165441,17 @@
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
const int MAX_NPREFIX = 10000000;
- const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
-
- for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
- nInt = nInt * 10 + (p[0] - '0');
- if( nInt>MAX_NPREFIX ){
- nInt = 0;
- break;
- }
+ int nByte;
+ nByte = sqlite3Fts3ReadInt(*pp, &nInt);
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
}
- if( p==*pp ) return SQLITE_ERROR;
+ if( nByte==0 ){
+ return SQLITE_ERROR;
+ }
*pnOut = nInt;
- *pp = p;
+ *pp += nByte;
return SQLITE_OK;
}
@@ -171518,10 +171533,7 @@
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
- nNear = 0;
- for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
- nNear = nNear * 10 + (zInput[nKey] - '0');
- }
+ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
}
}
@@ -177704,11 +177716,11 @@
if( zText ){
int i;
int iMul = 1;
- i64 iVal = 0;
+ u64 iVal = 0;
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *piEndBlock = iVal;
+ *piEndBlock = (i64)iVal;
while( zText[i]==' ' ) i++;
iVal = 0;
if( zText[i]=='-' ){
@@ -177718,7 +177730,7 @@
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *pnByte = (iVal * (i64)iMul);
+ *pnByte = ((i64)iVal * (i64)iMul);
}
}
@@ -227989,9 +228001,9 @@
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
/************** End of stmt.c ************************************************/
-#if __LINE__!=227992
+#if __LINE__!=228004
#undef SQLITE_SOURCE_ID
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt2"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt2"
#endif
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
diff --git a/amalgamation/sqlite3.h b/amalgamation/sqlite3.h
index 3152234..69ecb2f 100644
--- a/amalgamation/sqlite3.h
+++ b/amalgamation/sqlite3.h
@@ -125,7 +125,7 @@
*/
#define SQLITE_VERSION "3.31.1"
#define SQLITE_VERSION_NUMBER 3031001
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt1"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c
index 22afeff..27314d4 100644
--- a/amalgamation_dev/sqlite3.c
+++ b/amalgamation_dev/sqlite3.c
@@ -1167,7 +1167,7 @@
*/
#define SQLITE_VERSION "3.31.1"
#define SQLITE_VERSION_NUMBER 3031001
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt1"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -165176,6 +165176,7 @@
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -165909,6 +165910,22 @@
}
/*
+** Buffer z contains a positive integer value encoded as utf-8 text.
+** Decode this value and store it in *pnOut, returning the number of bytes
+** consumed. If an overflow error occurs return a negative value.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){
+ u64 iVal = 0;
+ int i;
+ for(i=0; z[i]>='0' && z[i]<='9'; i++){
+ iVal = iVal*10 + (z[i] - '0');
+ if( iVal>0x7FFFFFFF ) return -1;
+ }
+ *pnOut = (int)iVal;
+ return i;
+}
+
+/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
** sets *pp to point to the byte immediately following the last byte of
@@ -165923,19 +165940,17 @@
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
const int MAX_NPREFIX = 10000000;
- const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
-
- for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
- nInt = nInt * 10 + (p[0] - '0');
- if( nInt>MAX_NPREFIX ){
- nInt = 0;
- break;
- }
+ int nByte;
+ nByte = sqlite3Fts3ReadInt(*pp, &nInt);
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
}
- if( p==*pp ) return SQLITE_ERROR;
+ if( nByte==0 ){
+ return SQLITE_ERROR;
+ }
*pnOut = nInt;
- *pp = p;
+ *pp += nByte;
return SQLITE_OK;
}
@@ -172017,10 +172032,7 @@
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
- nNear = 0;
- for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
- nNear = nNear * 10 + (zInput[nKey] - '0');
- }
+ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
}
}
@@ -178203,11 +178215,11 @@
if( zText ){
int i;
int iMul = 1;
- i64 iVal = 0;
+ u64 iVal = 0;
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *piEndBlock = iVal;
+ *piEndBlock = (i64)iVal;
while( zText[i]==' ' ) i++;
iVal = 0;
if( zText[i]=='-' ){
@@ -178217,7 +178229,7 @@
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *pnByte = (iVal * (i64)iMul);
+ *pnByte = ((i64)iVal * (i64)iMul);
}
}
@@ -228488,9 +228500,9 @@
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
/************** End of stmt.c ************************************************/
-#if __LINE__!=228491
+#if __LINE__!=228503
#undef SQLITE_SOURCE_ID
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt2"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt2"
#endif
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
diff --git a/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h
index 3152234..69ecb2f 100644
--- a/amalgamation_dev/sqlite3.h
+++ b/amalgamation_dev/sqlite3.h
@@ -125,7 +125,7 @@
*/
#define SQLITE_VERSION "3.31.1"
#define SQLITE_VERSION_NUMBER 3031001
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 76d675fab066290ce32b220f3d96edfdbaa0ecca14cc39736efb7df23fe2alt1"
+#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 c1f3948f8bd6552e4936c1d0ca1c10d18a89b13843431f9f9c20ef69fc93alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index d03f3ad..841d744 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -963,6 +963,22 @@
}
/*
+** Buffer z contains a positive integer value encoded as utf-8 text.
+** Decode this value and store it in *pnOut, returning the number of bytes
+** consumed. If an overflow error occurs return a negative value.
+*/
+int sqlite3Fts3ReadInt(const char *z, int *pnOut){
+ u64 iVal = 0;
+ int i;
+ for(i=0; z[i]>='0' && z[i]<='9'; i++){
+ iVal = iVal*10 + (z[i] - '0');
+ if( iVal>0x7FFFFFFF ) return -1;
+ }
+ *pnOut = (int)iVal;
+ return i;
+}
+
+/*
** This function interprets the string at (*pp) as a non-negative integer
** value. It reads the integer and sets *pnOut to the value read, then
** sets *pp to point to the byte immediately following the last byte of
@@ -977,19 +993,17 @@
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
const int MAX_NPREFIX = 10000000;
- const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
-
- for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
- nInt = nInt * 10 + (p[0] - '0');
- if( nInt>MAX_NPREFIX ){
- nInt = 0;
- break;
- }
+ int nByte;
+ nByte = sqlite3Fts3ReadInt(*pp, &nInt);
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
}
- if( p==*pp ) return SQLITE_ERROR;
+ if( nByte==0 ){
+ return SQLITE_ERROR;
+ }
*pnOut = nInt;
- *pp = p;
+ *pp += nByte;
return SQLITE_OK;
}
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 50370a9..453afce 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -591,6 +591,7 @@
int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
+int sqlite3Fts3ReadInt(const char *z, int *pnOut);
/* fts3_tokenizer.c */
const char *sqlite3Fts3NextToken(const char *, int *);
diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c
index 5775fbc..e19137a 100644
--- a/ext/fts3/fts3_expr.c
+++ b/ext/fts3/fts3_expr.c
@@ -446,10 +446,7 @@
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
- nNear = 0;
- for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
- nNear = nNear * 10 + (zInput[nKey] - '0');
- }
+ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
}
}
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index 9a052a8..b9acc47 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -3069,11 +3069,11 @@
if( zText ){
int i;
int iMul = 1;
- i64 iVal = 0;
+ u64 iVal = 0;
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *piEndBlock = iVal;
+ *piEndBlock = (i64)iVal;
while( zText[i]==' ' ) i++;
iVal = 0;
if( zText[i]=='-' ){
@@ -3083,7 +3083,7 @@
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *pnByte = (iVal * (i64)iMul);
+ *pnByte = ((i64)iVal * (i64)iMul);
}
}
diff --git a/manifest b/manifest
index f94ce85..6e8cd76 100644
--- a/manifest
+++ b/manifest
@@ -82,11 +82,11 @@
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 2a9dd452003a143248e68449302da80dd0c43df72195b56577e3562e43c408a0
+F ext/fts3/fts3.c de2cc136ccc6128e948ffd5d74636756014b2430d6237d7002c3bc3ceb1ae3ae
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h f091030b976045e7df91af2337935952b477cdbd9f48058c44c965684484cb50
+F ext/fts3/fts3Int.h 2c59cc46aefde134c1782e89a6a5384710ddcd4e783071337aa5d43d07269be3
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
-F ext/fts3/fts3_expr.c b132af223e90e35b9f9efa9fe63d6ae737d34153a3b6066736086df8abc78a1f
+F ext/fts3/fts3_expr.c f081e38da641724cd72c20e23b71db2bf4d0c9517c14637442f6910259f11a34
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
@@ -100,7 +100,7 @@
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 4b9af6151c29b35ed09574937083cece7c31e911f69615e168a39677569b684d
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
-F ext/fts3/fts3_write.c d5da5f010b2e2c1523f0e359ec43858bb724f608d3805d0e2a82ca2b466eb22e
+F ext/fts3/fts3_write.c ed869b24d074f2498bdbef915d6db1f88c604ca5811502112061932a0bed5133
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
@@ -964,7 +964,7 @@
F test/fts3join.test 949b4f5ae3ae9cc2423cb865d711e32476bdb205ab2be923fdf48246e4a44166
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
-F test/fts3misc.test 236f37a57d97fa1b7e0a4303aab7e02da87a9818c106e513ae88af76f25ace4a
+F test/fts3misc.test 9ec15e7c0b5831a6353bd4c46bf3acdf1360eda5d9f396f667db4d05bcf92ecf
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
diff --git a/test/fts3misc.test b/test/fts3misc.test
index 9becba9..a1bec42 100644
--- a/test/fts3misc.test
+++ b/test/fts3misc.test
@@ -315,4 +315,12 @@
INSERT INTO f(f) VALUES ('merge=69,59');
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+do_execsql_test 11.0 {
+ CREATE VIRTUAL TABLE xyz USING fts3();
+}
+do_execsql_test 11.1 {
+ SELECT * FROM xyz WHERE xyz MATCH 'a NEAR/4294836224 a';
+}
+
finish_test