Index: src/test_stat.c ================================================================== --- src/test_stat.c +++ src/test_stat.c @@ -138,19 +138,27 @@ void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ - StatTable *pTab; - - pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable)); - memset(pTab, 0, sizeof(StatTable)); - pTab->db = db; - - sqlite3_declare_vtab(db, VTAB_SCHEMA); - *ppVtab = &pTab->base; - return SQLITE_OK; + StatTable *pTab = 0; + int rc = SQLITE_OK; + + rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); + if( rc==SQLITE_OK ){ + pTab = (StatTable *)sqlite3_malloc(sizeof(StatTable)); + if( pTab==0 ) rc = SQLITE_NOMEM; + } + + assert( rc==SQLITE_OK || pTab==0 ); + if( rc==SQLITE_OK ){ + memset(pTab, 0, sizeof(StatTable)); + pTab->db = db; + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; } /* ** Disconnect from or destroy a statvfs virtual table. */ @@ -194,36 +202,42 @@ StatTable *pTab = (StatTable *)pVTab; StatCursor *pCsr; int rc; pCsr = (StatCursor *)sqlite3_malloc(sizeof(StatCursor)); - memset(pCsr, 0, sizeof(StatCursor)); - pCsr->base.pVtab = pVTab; - - rc = sqlite3_prepare_v2(pTab->db, - "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" - " UNION ALL " - "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0" - " ORDER BY name", -1, - &pCsr->pStmt, 0 - ); - if( rc!=SQLITE_OK ){ - sqlite3_free(pCsr); - return rc; + if( pCsr==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr, 0, sizeof(StatCursor)); + pCsr->base.pVtab = pVTab; + + rc = sqlite3_prepare_v2(pTab->db, + "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" + " UNION ALL " + "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0" + " ORDER BY name", -1, + &pCsr->pStmt, 0 + ); + if( rc!=SQLITE_OK ){ + sqlite3_free(pCsr); + pCsr = 0; + } } *ppCursor = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; + return rc; } static void statClearPage(StatPage *p){ int i; - for(i=0; inCell; i++){ - sqlite3_free(p->aCell[i].aOvfl); + if( p->aCell ){ + for(i=0; inCell; i++){ + sqlite3_free(p->aCell[i].aOvfl); + } + sqlite3_free(p->aCell); } sqlite3PagerUnref(p->pPg); - sqlite3_free(p->aCell); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); } static void statResetCsr(StatCursor *pCsr){ @@ -305,10 +319,11 @@ sqlite3BtreeEnter(pBt); nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); + if( p->aCell==0 ) return SQLITE_NOMEM; memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); for(i=0; inCell; i++){ StatCell *pCell = &p->aCell[i]; @@ -337,10 +352,11 @@ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); + if( pCell->aOvfl==0 ) return SQLITE_NOMEM; pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); for(j=1; jaOvfl[j-1]; DbPage *pPg = 0; @@ -484,35 +500,37 @@ int i; StatPage *p = &pCsr->aPage[pCsr->iPage]; pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); pCsr->iPageno = p->iPgno; - statDecodePage(pBt, p); - statSizeAndOffset(pCsr); - - switch( p->flags ){ - case 0x05: /* table internal */ - case 0x02: /* index internal */ - pCsr->zPagetype = "internal"; - break; - case 0x0D: /* table leaf */ - case 0x0A: /* index leaf */ - pCsr->zPagetype = "leaf"; - break; - default: - pCsr->zPagetype = "corrupted"; - break; - } - pCsr->nCell = p->nCell; - pCsr->nUnused = p->nUnused; - pCsr->nMxPayload = p->nMxPayload; - pCsr->zPath = sqlite3_mprintf("%s", p->zPath); - nPayload = 0; - for(i=0; inCell; i++){ - nPayload += p->aCell[i].nLocal; - } - pCsr->nPayload = nPayload; + rc = statDecodePage(pBt, p); + if( rc==SQLITE_OK ){ + statSizeAndOffset(pCsr); + + switch( p->flags ){ + case 0x05: /* table internal */ + case 0x02: /* index internal */ + pCsr->zPagetype = "internal"; + break; + case 0x0D: /* table leaf */ + case 0x0A: /* index leaf */ + pCsr->zPagetype = "leaf"; + break; + default: + pCsr->zPagetype = "corrupted"; + break; + } + pCsr->nCell = p->nCell; + pCsr->nUnused = p->nUnused; + pCsr->nMxPayload = p->nMxPayload; + pCsr->zPath = sqlite3_mprintf("%s", p->zPath); + nPayload = 0; + for(i=0; inCell; i++){ + nPayload += p->aCell[i].nLocal; + } + pCsr->nPayload = nPayload; + } } return rc; } Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -6105,12 +6105,13 @@ pCur = allocateCursor(p, pOp->p1, 0, -1, 0); if( pCur ){ pCur->pVtabCursor = pVtabCursor; pVtab->nRef++; }else{ - db->mallocFailed = 1; + assert( db->mallocFailed ); pModule->xClose(pVtabCursor); + goto no_mem; } } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ ADDED test/statfault.test Index: test/statfault.test ================================================================== --- /dev/null +++ test/statfault.test @@ -0,0 +1,45 @@ +# 2015 April 28 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix statfault + +ifcapable !vtab||!compound { + finish_test + return +} + +register_dbstat_vtab db +do_execsql_test statfault-1 { + CREATE TABLE t1(a, b UNIQUE); + INSERT INTO t1 VALUES(1, randomblob(500)); + INSERT INTO t1 VALUES(randomblob(500), 1); + INSERT INTO t1 VALUES(2, randomblob(250)); + INSERT INTO t1 VALUES(randomblob(250), 2); + CREATE VIRTUAL TABLE sss USING dbstat; +} {} +faultsim_save_and_close + +do_faultsim_test 1 -faults * -prep { + faultsim_restore_and_reopen + register_dbstat_vtab db + execsql { SELECT 1 FROM sqlite_master LIMIT 1 } +} -body { + execsql { SELECT count(*) FROM sss } +} -test { + faultsim_test_result {0 8} +} + + +finish_test