Index: third_party/sqlite/src/src/printf.c |
diff --git a/third_party/sqlite/src/src/printf.c b/third_party/sqlite/src/src/printf.c |
index 387b9e90c18e241a983095429b235d0b2d95f1ec..969950c15484c9e4c8263923fb7b6554885688c8 100644 |
--- a/third_party/sqlite/src/src/printf.c |
+++ b/third_party/sqlite/src/src/printf.c |
@@ -1,31 +1,17 @@ |
/* |
** The "printf" code that follows dates from the 1980's. It is in |
-** the public domain. The original comments are included here for |
-** completeness. They are very out-of-date but might be useful as |
-** an historical reference. Most of the "enhancements" have been backed |
-** out so that the functionality is now the same as standard printf(). |
+** the public domain. |
** |
************************************************************************** |
** |
** This file contains code for a set of "printf"-like routines. These |
** routines format strings much like the printf() from the standard C |
** library, though the implementation here has enhancements to support |
-** SQLlite. |
+** SQLite. |
*/ |
#include "sqliteInt.h" |
/* |
-** If the strchrnul() library function is available, then set |
-** HAVE_STRCHRNUL. If that routine is not available, this module |
-** will supply its own. The built-in version is slower than |
-** the glibc version so the glibc version is definitely preferred. |
-*/ |
-#if !defined(HAVE_STRCHRNUL) |
-# define HAVE_STRCHRNUL 0 |
-#endif |
- |
- |
-/* |
** Conversion types fall into various categories as defined by the |
** following enumeration. |
*/ |
@@ -149,6 +135,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ |
** Set the StrAccum object to an error mode. |
*/ |
static void setStrAccumError(StrAccum *p, u8 eError){ |
+ assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); |
p->accError = eError; |
p->nAlloc = 0; |
} |
@@ -263,7 +250,6 @@ void sqlite3VXPrintf( |
} |
}while( !done && (c=(*++fmt))!=0 ); |
/* Get the field width */ |
- width = 0; |
if( c=='*' ){ |
if( bArgList ){ |
width = (int)getIntArg(pArgList); |
@@ -272,18 +258,27 @@ void sqlite3VXPrintf( |
} |
if( width<0 ){ |
flag_leftjustify = 1; |
- width = -width; |
+ width = width >= -2147483647 ? -width : 0; |
} |
c = *++fmt; |
}else{ |
+ unsigned wx = 0; |
while( c>='0' && c<='9' ){ |
- width = width*10 + c - '0'; |
+ wx = wx*10 + c - '0'; |
c = *++fmt; |
} |
+ testcase( wx>0x7fffffff ); |
+ width = wx & 0x7fffffff; |
+ } |
+ assert( width>=0 ); |
+#ifdef SQLITE_PRINTF_PRECISION_LIMIT |
+ if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ |
+ width = SQLITE_PRINTF_PRECISION_LIMIT; |
} |
+#endif |
+ |
/* Get the precision */ |
if( c=='.' ){ |
- precision = 0; |
c = *++fmt; |
if( c=='*' ){ |
if( bArgList ){ |
@@ -291,17 +286,30 @@ void sqlite3VXPrintf( |
}else{ |
precision = va_arg(ap,int); |
} |
- if( precision<0 ) precision = -precision; |
c = *++fmt; |
+ if( precision<0 ){ |
+ precision = precision >= -2147483647 ? -precision : -1; |
+ } |
}else{ |
+ unsigned px = 0; |
while( c>='0' && c<='9' ){ |
- precision = precision*10 + c - '0'; |
+ px = px*10 + c - '0'; |
c = *++fmt; |
} |
+ testcase( px>0x7fffffff ); |
+ precision = px & 0x7fffffff; |
} |
}else{ |
precision = -1; |
} |
+ assert( precision>=(-1) ); |
+#ifdef SQLITE_PRINTF_PRECISION_LIMIT |
+ if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ |
+ precision = SQLITE_PRINTF_PRECISION_LIMIT; |
+ } |
+#endif |
+ |
+ |
/* Get the conversion type modifier */ |
if( c=='l' ){ |
flag_long = 1; |
@@ -461,7 +469,8 @@ void sqlite3VXPrintf( |
else prefix = 0; |
} |
if( xtype==etGENERIC && precision>0 ) precision--; |
- for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){} |
+ testcase( precision>0xfff ); |
+ for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} |
if( xtype==etFLOAT ) realvalue += rounder; |
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ |
exp = 0; |
@@ -473,21 +482,16 @@ void sqlite3VXPrintf( |
if( realvalue>0.0 ){ |
LONGDOUBLE_TYPE scale = 1.0; |
while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} |
- while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; } |
- while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; } |
+ while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; } |
while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } |
realvalue /= scale; |
while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } |
while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } |
if( exp>350 ){ |
- if( prefix=='-' ){ |
- bufpt = "-Inf"; |
- }else if( prefix=='+' ){ |
- bufpt = "+Inf"; |
- }else{ |
- bufpt = "Inf"; |
- } |
- length = sqlite3Strlen30(bufpt); |
+ bufpt = buf; |
+ buf[0] = prefix; |
+ memcpy(buf+(prefix!=0),"Inf",4); |
+ length = 3+(prefix!=0); |
break; |
} |
} |
@@ -516,8 +520,9 @@ void sqlite3VXPrintf( |
}else{ |
e2 = exp; |
} |
- if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){ |
- bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 ); |
+ if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ |
+ bufpt = zExtra |
+ = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); |
if( bufpt==0 ){ |
setStrAccumError(pAccum, STRACCUM_NOMEM); |
return; |
@@ -635,12 +640,13 @@ void sqlite3VXPrintf( |
case etDYNSTRING: |
if( bArgList ){ |
bufpt = getTextArg(pArgList); |
+ xtype = etSTRING; |
}else{ |
bufpt = va_arg(ap,char*); |
} |
if( bufpt==0 ){ |
bufpt = ""; |
- }else if( xtype==etDYNSTRING && !bArgList ){ |
+ }else if( xtype==etDYNSTRING ){ |
zExtra = bufpt; |
} |
if( precision>=0 ){ |
@@ -649,9 +655,9 @@ void sqlite3VXPrintf( |
length = sqlite3Strlen30(bufpt); |
} |
break; |
- case etSQLESCAPE: |
- case etSQLESCAPE2: |
- case etSQLESCAPE3: { |
+ case etSQLESCAPE: /* Escape ' characters */ |
+ case etSQLESCAPE2: /* Escape ' and enclose in '...' */ |
+ case etSQLESCAPE3: { /* Escape " characters */ |
int i, j, k, n, isnull; |
int needQuote; |
char ch; |
@@ -670,7 +676,7 @@ void sqlite3VXPrintf( |
if( ch==q ) n++; |
} |
needQuote = !isnull && xtype==etSQLESCAPE2; |
- n += i + 1 + needQuote*2; |
+ n += i + 3; |
if( n>etBUFSIZE ){ |
bufpt = zExtra = sqlite3Malloc( n ); |
if( bufpt==0 ){ |
@@ -734,7 +740,7 @@ void sqlite3VXPrintf( |
if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); |
if( zExtra ){ |
- sqlite3_free(zExtra); |
+ sqlite3DbFree(pAccum->db, zExtra); |
zExtra = 0; |
} |
}/* End for loop over the format string */ |
@@ -749,20 +755,26 @@ void sqlite3VXPrintf( |
*/ |
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ |
char *zNew; |
- assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ |
+ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ |
if( p->accError ){ |
testcase(p->accError==STRACCUM_TOOBIG); |
testcase(p->accError==STRACCUM_NOMEM); |
return 0; |
} |
- if( !p->useMalloc ){ |
+ if( p->mxAlloc==0 ){ |
N = p->nAlloc - p->nChar - 1; |
setStrAccumError(p, STRACCUM_TOOBIG); |
return N; |
}else{ |
- char *zOld = (p->zText==p->zBase ? 0 : p->zText); |
+ char *zOld = p->bMalloced ? p->zText : 0; |
i64 szNew = p->nChar; |
+ assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); |
szNew += N + 1; |
+ if( szNew+p->nChar<=p->mxAlloc ){ |
+ /* Force exponential buffer size growth as long as it does not overflow, |
+ ** to avoid having to call this routine too often */ |
+ szNew += p->nChar; |
+ } |
if( szNew > p->mxAlloc ){ |
sqlite3StrAccumReset(p); |
setStrAccumError(p, STRACCUM_TOOBIG); |
@@ -770,15 +782,17 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ |
}else{ |
p->nAlloc = (int)szNew; |
} |
- if( p->useMalloc==1 ){ |
+ if( p->db ){ |
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); |
}else{ |
- zNew = sqlite3_realloc(zOld, p->nAlloc); |
+ zNew = sqlite3_realloc64(zOld, p->nAlloc); |
} |
if( zNew ){ |
assert( p->zText!=0 || p->nChar==0 ); |
- if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); |
+ if( !p->bMalloced && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); |
p->zText = zNew; |
+ p->nAlloc = sqlite3DbMallocSize(p->db, zNew); |
+ p->bMalloced = 1; |
}else{ |
sqlite3StrAccumReset(p); |
setStrAccumError(p, STRACCUM_NOMEM); |
@@ -792,7 +806,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ |
** Append N copies of character c to the given string buffer. |
*/ |
void sqlite3AppendChar(StrAccum *p, int N, char c){ |
- if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return; |
+ testcase( p->nChar + (i64)N > 0x7fffffff ); |
+ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ |
+ return; |
+ } |
+ assert( (p->zText==p->zBase)==(p->bMalloced==0) ); |
while( (N--)>0 ) p->zText[p->nChar++] = c; |
} |
@@ -810,6 +828,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ |
memcpy(&p->zText[p->nChar], z, N); |
p->nChar += N; |
} |
+ assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); |
} |
/* |
@@ -817,7 +836,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ |
** size of the memory allocation for StrAccum if necessary. |
*/ |
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ |
- assert( z!=0 ); |
+ assert( z!=0 || N==0 ); |
assert( p->zText!=0 || p->nChar==0 || p->accError ); |
assert( N>=0 ); |
assert( p->accError==0 || p->nAlloc==0 ); |
@@ -845,15 +864,13 @@ void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ |
*/ |
char *sqlite3StrAccumFinish(StrAccum *p){ |
if( p->zText ){ |
+ assert( (p->zText==p->zBase)==(p->bMalloced==0) ); |
p->zText[p->nChar] = 0; |
- if( p->useMalloc && p->zText==p->zBase ){ |
- if( p->useMalloc==1 ){ |
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); |
- }else{ |
- p->zText = sqlite3_malloc(p->nChar+1); |
- } |
+ if( p->mxAlloc>0 && p->bMalloced==0 ){ |
+ p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); |
if( p->zText ){ |
memcpy(p->zText, p->zBase, p->nChar+1); |
+ p->bMalloced = 1; |
}else{ |
setStrAccumError(p, STRACCUM_NOMEM); |
} |
@@ -866,27 +883,36 @@ char *sqlite3StrAccumFinish(StrAccum *p){ |
** Reset an StrAccum string. Reclaim all malloced memory. |
*/ |
void sqlite3StrAccumReset(StrAccum *p){ |
- if( p->zText!=p->zBase ){ |
- if( p->useMalloc==1 ){ |
- sqlite3DbFree(p->db, p->zText); |
- }else{ |
- sqlite3_free(p->zText); |
- } |
+ assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); |
+ if( p->bMalloced ){ |
+ sqlite3DbFree(p->db, p->zText); |
+ p->bMalloced = 0; |
} |
p->zText = 0; |
} |
/* |
-** Initialize a string accumulator |
+** Initialize a string accumulator. |
+** |
+** p: The accumulator to be initialized. |
+** db: Pointer to a database connection. May be NULL. Lookaside |
+** memory is used if not NULL. db->mallocFailed is set appropriately |
+** when not NULL. |
+** zBase: An initial buffer. May be NULL in which case the initial buffer |
+** is malloced. |
+** n: Size of zBase in bytes. If total space requirements never exceed |
+** n then no memory allocations ever occur. |
+** mx: Maximum number of bytes to accumulate. If mx==0 then no memory |
+** allocations will ever occur. |
*/ |
-void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){ |
+void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ |
p->zText = p->zBase = zBase; |
- p->db = 0; |
+ p->db = db; |
p->nChar = 0; |
p->nAlloc = n; |
p->mxAlloc = mx; |
- p->useMalloc = 1; |
p->accError = 0; |
+ p->bMalloced = 0; |
} |
/* |
@@ -898,9 +924,8 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ |
char zBase[SQLITE_PRINT_BUF_SIZE]; |
StrAccum acc; |
assert( db!=0 ); |
- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), |
+ sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), |
db->aLimit[SQLITE_LIMIT_LENGTH]); |
- acc.db = db; |
sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap); |
z = sqlite3StrAccumFinish(&acc); |
if( acc.accError==STRACCUM_NOMEM ){ |
@@ -923,24 +948,6 @@ char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ |
} |
/* |
-** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting |
-** the string and before returning. This routine is intended to be used |
-** to modify an existing string. For example: |
-** |
-** x = sqlite3MPrintf(db, x, "prefix %s suffix", x); |
-** |
-*/ |
-char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){ |
- va_list ap; |
- char *z; |
- va_start(ap, zFormat); |
- z = sqlite3VMPrintf(db, zFormat, ap); |
- va_end(ap); |
- sqlite3DbFree(db, zStr); |
- return z; |
-} |
- |
-/* |
** Print into memory obtained from sqlite3_malloc(). Omit the internal |
** %-conversion extensions. |
*/ |
@@ -948,11 +955,17 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){ |
char *z; |
char zBase[SQLITE_PRINT_BUF_SIZE]; |
StrAccum acc; |
+ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( zFormat==0 ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
#ifndef SQLITE_OMIT_AUTOINIT |
if( sqlite3_initialize() ) return 0; |
#endif |
- sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); |
- acc.useMalloc = 2; |
+ sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); |
sqlite3VXPrintf(&acc, 0, zFormat, ap); |
z = sqlite3StrAccumFinish(&acc); |
return z; |
@@ -990,8 +1003,14 @@ char *sqlite3_mprintf(const char *zFormat, ...){ |
char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ |
StrAccum acc; |
if( n<=0 ) return zBuf; |
- sqlite3StrAccumInit(&acc, zBuf, n, 0); |
- acc.useMalloc = 0; |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( zBuf==0 || zFormat==0 ) { |
+ (void)SQLITE_MISUSE_BKPT; |
+ if( zBuf ) zBuf[0] = 0; |
+ return zBuf; |
+ } |
+#endif |
+ sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); |
sqlite3VXPrintf(&acc, 0, zFormat, ap); |
return sqlite3StrAccumFinish(&acc); |
} |
@@ -1012,13 +1031,17 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ |
** sqlite3_log() must render into a static buffer. It cannot dynamically |
** allocate memory because it might be called while the memory allocator |
** mutex is held. |
+** |
+** sqlite3VXPrintf() might ask for *temporary* memory allocations for |
+** certain format characters (%q) or for very large precisions or widths. |
+** Care must be taken that any sqlite3_log() calls that occur while the |
+** memory mutex is held do not use these mechanisms. |
*/ |
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ |
StrAccum acc; /* String accumulator */ |
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ |
- sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0); |
- acc.useMalloc = 0; |
+ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); |
sqlite3VXPrintf(&acc, 0, zFormat, ap); |
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, |
sqlite3StrAccumFinish(&acc)); |
@@ -1036,7 +1059,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...){ |
} |
} |
-#if defined(SQLITE_DEBUG) |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
/* |
** A version of printf() that understands %lld. Used for debugging. |
** The printf() built into some versions of windows does not understand %lld |
@@ -1046,8 +1069,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ |
va_list ap; |
StrAccum acc; |
char zBuf[500]; |
- sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); |
- acc.useMalloc = 0; |
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); |
va_start(ap,zFormat); |
sqlite3VXPrintf(&acc, 0, zFormat, ap); |
va_end(ap); |
@@ -1057,71 +1079,10 @@ void sqlite3DebugPrintf(const char *zFormat, ...){ |
} |
#endif |
-#ifdef SQLITE_DEBUG |
-/************************************************************************* |
-** Routines for implementing the "TreeView" display of hierarchical |
-** data structures for debugging. |
-** |
-** The main entry points (coded elsewhere) are: |
-** sqlite3TreeViewExpr(0, pExpr, 0); |
-** sqlite3TreeViewExprList(0, pList, 0, 0); |
-** sqlite3TreeViewSelect(0, pSelect, 0); |
-** Insert calls to those routines while debugging in order to display |
-** a diagram of Expr, ExprList, and Select objects. |
-** |
-*/ |
-/* Add a new subitem to the tree. The moreToFollow flag indicates that this |
-** is not the last item in the tree. */ |
-TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ |
- if( p==0 ){ |
- p = sqlite3_malloc( sizeof(*p) ); |
- if( p==0 ) return 0; |
- memset(p, 0, sizeof(*p)); |
- }else{ |
- p->iLevel++; |
- } |
- assert( moreToFollow==0 || moreToFollow==1 ); |
- if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; |
- return p; |
-} |
-/* Finished with one layer of the tree */ |
-void sqlite3TreeViewPop(TreeView *p){ |
- if( p==0 ) return; |
- p->iLevel--; |
- if( p->iLevel<0 ) sqlite3_free(p); |
-} |
-/* Generate a single line of output for the tree, with a prefix that contains |
-** all the appropriate tree lines */ |
-void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ |
- va_list ap; |
- int i; |
- StrAccum acc; |
- char zBuf[500]; |
- sqlite3StrAccumInit(&acc, zBuf, sizeof(zBuf), 0); |
- acc.useMalloc = 0; |
- if( p ){ |
- for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ |
- sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); |
- } |
- sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); |
- } |
- va_start(ap, zFormat); |
- sqlite3VXPrintf(&acc, 0, zFormat, ap); |
- va_end(ap); |
- if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); |
- sqlite3StrAccumFinish(&acc); |
- fprintf(stdout,"%s", zBuf); |
- fflush(stdout); |
-} |
-/* Shorthand for starting a new tree item that consists of a single label */ |
-void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){ |
- p = sqlite3TreeViewPush(p, moreToFollow); |
- sqlite3TreeViewLine(p, "%s", zLabel); |
-} |
-#endif /* SQLITE_DEBUG */ |
/* |
-** variable-argument wrapper around sqlite3VXPrintf(). |
+** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument |
+** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. |
*/ |
void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){ |
va_list ap; |