| Index: third_party/sqlite/src/src/malloc.c
|
| diff --git a/third_party/sqlite/src/src/malloc.c b/third_party/sqlite/src/src/malloc.c
|
| index 2c493b93201734658b18684d5c3dde7d892d00c2..e7714aa103a46b226e1d41bc9e92571b0c07929e 100644
|
| --- a/third_party/sqlite/src/src/malloc.c
|
| +++ b/third_party/sqlite/src/src/malloc.c
|
| @@ -217,11 +217,19 @@ static void sqlite3MallocAlarm(int nByte){
|
| ** Do a memory allocation with statistics and alarms. Assume the
|
| ** lock is already held.
|
| */
|
| -static int mallocWithAlarm(int n, void **pp){
|
| - int nFull;
|
| +static void mallocWithAlarm(int n, void **pp){
|
| void *p;
|
| + int nFull;
|
| assert( sqlite3_mutex_held(mem0.mutex) );
|
| + assert( n>0 );
|
| +
|
| + /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal
|
| + ** implementation of malloc_good_size(), which must be called in debug
|
| + ** mode and specifically when the DMD "Dark Matter Detector" is enabled
|
| + ** or else a crash results. Hence, do not attempt to optimize out the
|
| + ** following xRoundup() call. */
|
| nFull = sqlite3GlobalConfig.m.xRoundup(n);
|
| +
|
| sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
|
| if( mem0.alarmThreshold>0 ){
|
| sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
| @@ -245,7 +253,6 @@ static int mallocWithAlarm(int n, void **pp){
|
| sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
|
| }
|
| *pp = p;
|
| - return nFull;
|
| }
|
|
|
| /*
|
| @@ -519,7 +526,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
|
| sqlite3_mutex_enter(mem0.mutex);
|
| sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
|
| nDiff = nNew - nOld;
|
| - if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
|
| + if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
|
| mem0.alarmThreshold-nDiff ){
|
| sqlite3MallocAlarm(nDiff);
|
| }
|
| @@ -575,16 +582,31 @@ void *sqlite3MallocZero(u64 n){
|
| ** the mallocFailed flag in the connection pointer.
|
| */
|
| void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
|
| - void *p = sqlite3DbMallocRaw(db, n);
|
| - if( p ){
|
| - memset(p, 0, (size_t)n);
|
| - }
|
| + void *p;
|
| + testcase( db==0 );
|
| + p = sqlite3DbMallocRaw(db, n);
|
| + if( p ) memset(p, 0, (size_t)n);
|
| + return p;
|
| +}
|
| +
|
| +
|
| +/* Finish the work of sqlite3DbMallocRawNN for the unusual and
|
| +** slower case when the allocation cannot be fulfilled using lookaside.
|
| +*/
|
| +static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
|
| + void *p;
|
| + assert( db!=0 );
|
| + p = sqlite3Malloc(n);
|
| + if( !p ) sqlite3OomFault(db);
|
| + sqlite3MemdebugSetType(p,
|
| + (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
|
| return p;
|
| }
|
|
|
| /*
|
| -** Allocate and zero memory. If the allocation fails, make
|
| -** the mallocFailed flag in the connection pointer.
|
| +** Allocate memory, either lookaside (if possible) or heap.
|
| +** If the allocation fails, set the mallocFailed flag in
|
| +** the connection pointer.
|
| **
|
| ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
|
| ** failure on the same database connection) then always return 0.
|
| @@ -599,64 +621,73 @@ void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
|
| **
|
| ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
|
| ** that all prior mallocs (ex: "a") worked too.
|
| +**
|
| +** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
|
| +** not a NULL pointer.
|
| */
|
| void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
|
| void *p;
|
| - assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
| - assert( db==0 || db->pnBytesFreed==0 );
|
| + if( db ) return sqlite3DbMallocRawNN(db, n);
|
| + p = sqlite3Malloc(n);
|
| + sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
| + return p;
|
| +}
|
| +void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
|
| #ifndef SQLITE_OMIT_LOOKASIDE
|
| - if( db ){
|
| - LookasideSlot *pBuf;
|
| - if( db->mallocFailed ){
|
| - return 0;
|
| - }
|
| - if( db->lookaside.bEnabled ){
|
| - if( n>db->lookaside.sz ){
|
| - db->lookaside.anStat[1]++;
|
| - }else if( (pBuf = db->lookaside.pFree)==0 ){
|
| - db->lookaside.anStat[2]++;
|
| - }else{
|
| - db->lookaside.pFree = pBuf->pNext;
|
| - db->lookaside.nOut++;
|
| - db->lookaside.anStat[0]++;
|
| - if( db->lookaside.nOut>db->lookaside.mxOut ){
|
| - db->lookaside.mxOut = db->lookaside.nOut;
|
| - }
|
| - return (void*)pBuf;
|
| + LookasideSlot *pBuf;
|
| + assert( db!=0 );
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + assert( db->pnBytesFreed==0 );
|
| + if( db->lookaside.bDisable==0 ){
|
| + assert( db->mallocFailed==0 );
|
| + if( n>db->lookaside.sz ){
|
| + db->lookaside.anStat[1]++;
|
| + }else if( (pBuf = db->lookaside.pFree)==0 ){
|
| + db->lookaside.anStat[2]++;
|
| + }else{
|
| + db->lookaside.pFree = pBuf->pNext;
|
| + db->lookaside.nOut++;
|
| + db->lookaside.anStat[0]++;
|
| + if( db->lookaside.nOut>db->lookaside.mxOut ){
|
| + db->lookaside.mxOut = db->lookaside.nOut;
|
| }
|
| + return (void*)pBuf;
|
| }
|
| + }else if( db->mallocFailed ){
|
| + return 0;
|
| }
|
| #else
|
| - if( db && db->mallocFailed ){
|
| + assert( db!=0 );
|
| + assert( sqlite3_mutex_held(db->mutex) );
|
| + assert( db->pnBytesFreed==0 );
|
| + if( db->mallocFailed ){
|
| return 0;
|
| }
|
| #endif
|
| - p = sqlite3Malloc(n);
|
| - if( !p && db ){
|
| - db->mallocFailed = 1;
|
| - }
|
| - sqlite3MemdebugSetType(p,
|
| - (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
|
| - return p;
|
| + return dbMallocRawFinish(db, n);
|
| }
|
|
|
| +/* Forward declaration */
|
| +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
|
| +
|
| /*
|
| ** Resize the block of memory pointed to by p to n bytes. If the
|
| ** resize fails, set the mallocFailed flag in the connection object.
|
| */
|
| void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
|
| - void *pNew = 0;
|
| assert( db!=0 );
|
| + if( p==0 ) return sqlite3DbMallocRawNN(db, n);
|
| assert( sqlite3_mutex_held(db->mutex) );
|
| + if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
|
| + return dbReallocFinish(db, p, n);
|
| +}
|
| +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
|
| + void *pNew = 0;
|
| + assert( db!=0 );
|
| + assert( p!=0 );
|
| if( db->mallocFailed==0 ){
|
| - if( p==0 ){
|
| - return sqlite3DbMallocRaw(db, n);
|
| - }
|
| if( isLookaside(db, p) ){
|
| - if( n<=db->lookaside.sz ){
|
| - return p;
|
| - }
|
| - pNew = sqlite3DbMallocRaw(db, n);
|
| + pNew = sqlite3DbMallocRawNN(db, n);
|
| if( pNew ){
|
| memcpy(pNew, p, db->lookaside.sz);
|
| sqlite3DbFree(db, p);
|
| @@ -667,10 +698,10 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
|
| sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
| pNew = sqlite3_realloc64(p, n);
|
| if( !pNew ){
|
| - db->mallocFailed = 1;
|
| + sqlite3OomFault(db);
|
| }
|
| sqlite3MemdebugSetType(pNew,
|
| - (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
|
| + (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
|
| }
|
| }
|
| return pNew;
|
| @@ -702,9 +733,8 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
| if( z==0 ){
|
| return 0;
|
| }
|
| - n = sqlite3Strlen30(z) + 1;
|
| - assert( (n&0x7fffffff)==n );
|
| - zNew = sqlite3DbMallocRaw(db, (int)n);
|
| + n = strlen(z) + 1;
|
| + zNew = sqlite3DbMallocRaw(db, n);
|
| if( zNew ){
|
| memcpy(zNew, z, n);
|
| }
|
| @@ -712,11 +742,12 @@ char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
| }
|
| char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
| char *zNew;
|
| + assert( db!=0 );
|
| if( z==0 ){
|
| return 0;
|
| }
|
| assert( (n&0x7fffffff)==n );
|
| - zNew = sqlite3DbMallocRaw(db, n+1);
|
| + zNew = sqlite3DbMallocRawNN(db, n+1);
|
| if( zNew ){
|
| memcpy(zNew, z, (size_t)n);
|
| zNew[n] = 0;
|
| @@ -733,12 +764,44 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
|
| }
|
|
|
| /*
|
| +** Call this routine to record the fact that an OOM (out-of-memory) error
|
| +** has happened. This routine will set db->mallocFailed, and also
|
| +** temporarily disable the lookaside memory allocator and interrupt
|
| +** any running VDBEs.
|
| +*/
|
| +void sqlite3OomFault(sqlite3 *db){
|
| + if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
|
| + db->mallocFailed = 1;
|
| + if( db->nVdbeExec>0 ){
|
| + db->u1.isInterrupted = 1;
|
| + }
|
| + db->lookaside.bDisable++;
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** This routine reactivates the memory allocator and clears the
|
| +** db->mallocFailed flag as necessary.
|
| +**
|
| +** The memory allocator is not restarted if there are running
|
| +** VDBEs.
|
| +*/
|
| +void sqlite3OomClear(sqlite3 *db){
|
| + if( db->mallocFailed && db->nVdbeExec==0 ){
|
| + db->mallocFailed = 0;
|
| + db->u1.isInterrupted = 0;
|
| + assert( db->lookaside.bDisable>0 );
|
| + db->lookaside.bDisable--;
|
| + }
|
| +}
|
| +
|
| +/*
|
| ** Take actions at the end of an API call to indicate an OOM error
|
| */
|
| static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
|
| - db->mallocFailed = 0;
|
| + sqlite3OomClear(db);
|
| sqlite3Error(db, SQLITE_NOMEM);
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
|
|
| /*
|
|
|