1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Many small changes to ensure memory is not leaked after malloc() fails. (CVS 2808)

FossilOrigin-Name: 601c335463aaabc2e9918e4b9298cff6161be5c4
This commit is contained in:
danielk1977
2005-12-09 14:25:08 +00:00
parent fde4a6f8a4
commit 2e588c7525
18 changed files with 848 additions and 423 deletions

View File

@ -1,5 +1,5 @@
C Add\smore\sstress\stesting\sto\sautovacuum\sin\san\s(unsuccessful)\sattempt\sto\nreproduce\sa\sreported\sproblem.\s\sEven\sthough\sthese\stests\sdid\snot\suncover\nanything\samiss,\sextra\stests\snever\shurt...\s(CVS\s2807)
D 2005-12-09T02:35:54
C Many\ssmall\schanges\sto\sensure\smemory\sis\snot\sleaked\safter\smalloc()\sfails.\s(CVS\s2808)
D 2005-12-09T14:25:08
F Makefile.in e3c6b3a38d734d41574c04f2fc90d18de2b87102
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -32,7 +32,7 @@ F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/alter.c 7ed4b794c2e3a8ad8c1effe50202eaef42cedc23
F src/analyze.c ea42005eed52c382fcc7ef66969e7f1858597633
F src/attach.c 39e678033d0be197dea4e9d5eeac2b2df51d6c9f
F src/attach.c ee70131f128d31a9c6dcb8824e8471c91b18601a
F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
F src/btree.c aa88194f460becf8fff6196996d6e38f1b37286e
F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e
@ -55,7 +55,7 @@ F src/os.h d5ae3f4c1c7731437b6cddec279b7c06f761c44e
F src/os_common.h d74a11728ad2444b6b695b94c28c06881f049e49
F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
F src/os_unix.c 76189e4cb5e1ad451293ce1aeb348c3b829e7e13
F src/os_unix.c 01648f7fa16cddb1f8a11ef2a582348801b185a6
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c d962ac2dd0e482847e42b846d46cd044f97d1c32
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
@ -63,32 +63,32 @@ F src/pager.c 893cb2106261a4f77d84c1fa0d10a083e889b23b
F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
F src/parse.y 87080d89439925de19f16189310d3dbc7f9ab3f6
F src/pragma.c a6d3a7c76b4008b8197913de4bd2079e00b145db
F src/prepare.c e93967011379051316728d316755f533a9bb438c
F src/prepare.c 7e21ab5e2304e76f5f679d0df19dca3b0e3ff4f2
F src/printf.c 3ea3a17d25d7ac498efc18007c70371a42c968f8
F src/random.c ff5e9a8cad790e2a51cd4d2e7737dc8540e09d1d
F src/select.c 0e4d3627fec4a445b45f6cb471f68aab9c97a8b3
F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
F src/shell.c 4872acee1d2a826c73c914961e469e563204b7f9
F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2
F src/sqliteInt.h bbc310a83a32476aa960055a166af4a0ef503a79
F src/sqliteInt.h 4247cf9ae4280ae33e5bbc7b45358940ff34b9ce
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c 328060916c24d328cfab1622c9a0e7ad57c2da8c
F src/test1.c 0b4bf8ab9afb37f34a83c46f81de54adf519b23d
F src/test1.c 350129da26943dd62067e75ad71ba85a1a648230
F src/test2.c 36390cdfc70c08e5ee0b466d0654a117f398bbff
F src/test3.c f4e6a16a602091696619a1171bda25c0e3df49f7
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/test6.c cb811391ec0b7c75f29e545d4820a9cf19f3637e
F src/tokenize.c a189d7466524076220f41a21baed05e1639a82f4
F src/trigger.c 388c13a2f07584decdb88413a63017391f9a7f7a
F src/trigger.c dfc1f8ee8e71c6482fb269695778c8b51f821c98
F src/update.c ec8e540617b116725b5a55c8d6b4db8bc67fdd7d
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 88ebafb5708f04002e58a373386e3c8c31bfd858
F src/vacuum.c 4d64ce98a4cb130002cbf8aba018b2567773e6b1
F src/vdbe.c 7f4a2affee140b7b57952ab2c081a9c22b950638
F src/util.c c77727365ce60b0e0087550ba88653ad0fcf24ea
F src/vacuum.c 3cd457f91b05338269f2ea21c4c58dce93f2eef2
F src/vdbe.c 4f78f1fe3b5e7675ee54a2cc18f14dea4ff5fd94
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
F src/vdbeInt.h 0055c37eccbf3a189fd893a90f8eb6a5fa60c871
F src/vdbeapi.c b80b3a1e8bf7866d96ca76d91bba979155bace57
F src/vdbeaux.c 90143aaffbe232a700fd05e4b2e7428d512b605b
F src/vdbeapi.c b270b680cbc5d20b5a1abfdb08339667985df94e
F src/vdbeaux.c b0a4a4b19b42f18d86c0026a9cc548478dc6a7a7
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 1c70555d615c6001c4490dedb6a62cb2884b92ff
F src/where.c 269569f380ddc018518f67765fe2f0d3c8760e28
@ -180,8 +180,8 @@ F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
F test/main.test b12f01d49a5c805a33fa6c0ef168691f63056e79
F test/malloc.test a5ed721cf7d1b12602ede4f98c11b65ab1582cc0
F test/malloc2.test e6e321db96d6c94cb18bf82ad7215070c41e624e
F test/malloc3.test 0d60a9d19196581e9279c2d040bebd8162ab495b
F test/malloc4.test 593ae91bf69ab5abc68f7652e679e5d207e23166
F test/malloc3.test 56372aafe58cc24a31bad4b24ff3f77cf1cc30ab
F test/malloc4.test 2e29d155eb4b4808019ef47eeedfcbe9e09e0f05
F test/manydb.test d81debbf5871242e3b5df1d3bb5e14c50431b6f8
F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea
F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac
@ -208,7 +208,7 @@ F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
F test/rowid.test 040a3bef06f970c45f5fcd14b2355f7f4d62f0cf
F test/safety.test 907b64fee719554a3622853812af3886fddbbb4f
F test/schema.test 8a2ae440fb15f5798a68059e8746402f3137be46
F test/select1.test 480233d4f5a81d7d59a55e40d05084d97e57ecdf
F test/select1.test 20275797efe032a56e97687aa06ba65d7a0b9b2b
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
F test/select3.test 8fece41cd8f2955131b3f973a7123bec60b6e65e
F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
@ -223,7 +223,7 @@ F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
F test/tclsqlite.test 2da3e4b3a79b13c1511c9d0cd995e08f8362e782
F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
F test/tester.tcl 1dbcac19ed71f68f24b7f5c6c134568d551092ba
F test/tester.tcl 6effe753bed26313eaab11a382436a99e602fa54
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
@ -327,7 +327,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P a7c9e8989c752f6b1148e7cc7bf59bbd8b402e87
R 0c1000cc2ea9df5aafb3433db2962046
U drh
Z 44f91e86d2b44a0b3e1c8417c9a4606c
P d8a8933ff30b83c0483be214403d92c4dfa9a4af
R 208b8157372f7c8db3da02b392e698f6
U danielk1977
Z 1ece2b1e923caae0853519e926a399e9

View File

@ -1 +1 @@
d8a8933ff30b83c0483be214403d92c4dfa9a4af
601c335463aaabc2e9918e4b9298cff6161be5c4

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.36 2005/12/06 17:19:11 danielk1977 Exp $
** $Id: attach.c,v 1.37 2005/12/09 14:25:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -261,13 +261,18 @@ static void codeAttach(
sqlite3* db = pParse->db;
#ifndef SQLITE_OMIT_AUTHORIZATION
assert( sqlite3Tsd()->mallocFailed || pAuthArg );
if( pAuthArg ){
char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
if( !zAuthArg ){
goto attach_end;
}
if( sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0)!=SQLITE_OK ){
rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
sqliteFree(zAuthArg);
if(rc!=SQLITE_OK ){
goto attach_end;
}
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
memset(&sName, 0, sizeof(NameContext));
@ -304,7 +309,6 @@ attach_end:
sqlite3ExprDelete(pFilename);
sqlite3ExprDelete(pDbname);
sqlite3ExprDelete(pKey);
sqliteFree(zAuthArg);
}
/*

View File

@ -633,6 +633,7 @@ static int unixOpenReadWrite(
static int unixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
int rc;
unixFile f;
int fd;
assert( 0==*pId );
if( access(zFilename, 0)==0 ){
@ -1485,6 +1486,8 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){
pNew = sqliteMalloc( sizeof(unixFile) );
if( pNew==0 ){
close(pInit->h);
releaseLockInfo(pInit->pLock);
releaseOpenCnt(pInit->pOpen);
*pId = 0;
return SQLITE_NOMEM;
}else{

View File

@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.5 2005/12/06 12:52:59 danielk1977 Exp $
** $Id: prepare.c,v 1.6 2005/12/09 14:25:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -503,7 +503,7 @@ prepare_out:
sqlite3Error(db, rc, 0);
}
sqlite3ClearMallocFailed();
sqlite3MallocClearFailed();
return rc;
}

View File

@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.128 2005/09/11 02:03:04 drh Exp $
** $Id: shell.c,v 1.129 2005/12/09 14:25:08 danielk1977 Exp $
*/
#include <stdlib.h>
#include <string.h>
@ -81,7 +81,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
/*
** Determines if a string is a number of not.
*/
static int isNumber(const unsigned char *z, int *realnum){
static int isNumber(const char *z, int *realnum){
if( *z=='-' || *z=='+' ) z++;
if( !isdigit(*z) ){
return 0;
@ -690,8 +690,9 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
rc = sqlite3_step(pTableInfo);
while( rc==SQLITE_ROW ){
const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
zSelect = appendText(zSelect, "quote(", 0);
zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"');
zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){
zSelect = appendText(zSelect, ") || ', ' || ", 0);

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.430 2005/12/06 17:19:11 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.431 2005/12/09 14:25:08 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -233,47 +233,46 @@ struct BusyHandler {
*/
#define Addr(X) ((uptr)X)
/*
** If memory allocation problems are found, recompile with
**
** -DSQLITE_DEBUG=1
**
** to enable some sanity checking on malloc() and free(). To
** check for memory leaks, recompile with
**
** -DSQLITE_DEBUG=2
**
** and a line of text will be written to standard error for
** each malloc() and free(). This output can be analyzed
** by an AWK script to determine if there are any leaks.
*/
#ifdef SQLITE_MEMDEBUG
# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__)
# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__)
# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__)
# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__)
# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__)
#else
# define sqliteFree sqlite3FreeX
# define sqliteMalloc sqlite3Malloc
# define sqliteMallocRaw sqlite3MallocRaw
# define sqliteRealloc sqlite3Realloc
# define sqliteStrDup sqlite3StrDup
# define sqliteStrNDup sqlite3StrNDup
#endif
/*
** The following global variables are used for testing and debugging
** only. They only work if SQLITE_DEBUG is defined.
*/
#ifdef SQLITE_MEMDEBUG
extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
extern int sqlite3_nFree; /* Number of sqliteFree() calls */
extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
#define ENTER_MALLOC (\
sqlite3Tsd()->zFile = __FILE__, sqlite3Tsd()->iLine = __LINE__ \
)
#else
#define ENTER_MALLOC 0
#endif
#define sqliteFree(x) sqlite3FreeX(x)
#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x))
#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x))
#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y))
#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x))
#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y))
/*
** An instance of this structure is allocated for each thread that uses SQLite.
*/
typedef struct SqliteTsd SqliteTsd;
struct SqliteTsd {
int mallocFailed; /* True after a malloc() has failed */
#ifndef NDEBUG
int mallocAllowed; /* assert() in sqlite3Malloc() if not set */
#endif
#ifdef SQLITE_MEMDEBUG
int isFail; /* True if all malloc() calls should fail */
const char *zFile; /* Filename to associate debugging info with */
int iLine; /* Line number to associate debugging info with */
void *pFirst; /* Pointer to linked list of allocations */
#endif
};
/*
** Name of the master database table. The master database table
** is a special table that holds the names and attributes of all
@ -1379,14 +1378,6 @@ typedef struct {
char **pzErrMsg; /* Error message stored here */
} InitData;
/*
** An instance of this structure is allocated for each thread that uses SQLite.
*/
typedef struct SqliteTsd SqliteTsd;
struct SqliteTsd {
int mallocFailed; /* True after a malloc() has failed */
};
/*
* This global flag is set for performance testing of triggers. When it is set
* SQLite will perform the overhead of building new and old trigger references
@ -1417,14 +1408,7 @@ int sqlite3IsNumber(const char*, int*, u8);
int sqlite3Compare(const char *, const char *);
int sqlite3SortCompare(const char *, const char *);
void sqlite3RealToSortable(double r, char *);
#ifdef SQLITE_MEMDEBUG
void *sqlite3Malloc_(int,int,char*,int);
void sqlite3Free_(void*,char*,int);
void *sqlite3Realloc_(void*,int,char*,int);
char *sqlite3StrDup_(const char*,char*,int);
char *sqlite3StrNDup_(const char*, int,char*,int);
void sqlite3CheckMemory(void*,int);
#else
void *sqlite3Malloc(int);
void *sqlite3MallocRaw(int);
void sqlite3Free(void*);
@ -1432,11 +1416,10 @@ void sqlite3RealToSortable(double r, char *);
char *sqlite3StrDup(const char*);
char *sqlite3StrNDup(const char*, int);
# define sqlite3CheckMemory(a,b)
# define sqlite3MallocX sqlite3Malloc
#endif
void sqlite3ReallocOrFree(void**,int);
void sqlite3FreeX(void*);
void *sqlite3MallocX(int);
char *sqlite3MPrintf(const char*, ...);
char *sqlite3VMPrintf(const char*, va_list);
void sqlite3DebugPrintf(const char*, ...);
@ -1677,9 +1660,17 @@ void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
SqliteTsd *sqlite3Tsd();
void sqlite3ClearMallocFailed();
void sqlite3AttachFunctions(sqlite3 *);
void sqlite3MallocClearFailed();
#ifdef NDEBUG
#define sqlite3MallocDisallow()
#define sqlite3MallocAllow()
#else
void sqlite3MallocDisallow();
void sqlite3MallocAllow();
#endif
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.171 2005/12/06 12:53:00 danielk1977 Exp $
** $Id: test1.c,v 1.172 2005/12/09 14:25:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -832,6 +832,15 @@ static int sqlite_malloc_stat(
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
static int sqlite_malloc_outstanding(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
char **argv /* Text of each argument */
){
extern int sqlite3OutstandingMallocs(Tcl_Interp *interp);
return sqlite3OutstandingMallocs(interp);
}
#endif
/*
@ -3082,6 +3091,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#ifdef SQLITE_MEMDEBUG
{ "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
{ "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
{ "sqlite_malloc_outstanding", (Tcl_CmdProc*)sqlite_malloc_outstanding},
#endif
{ "sqlite_bind", (Tcl_CmdProc*)test_bind },
{ "breakpoint", (Tcl_CmdProc*)test_breakpoint },
@ -3176,6 +3186,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_sync_count, sqlite3_fullsync_count;
extern int sqlite3_opentemp_count;
extern int sqlite3_memUsed;
extern int sqlite3_malloc_id;
extern int sqlite3_memMax;
extern int sqlite3_like_count;
#if OS_WIN
@ -3210,6 +3221,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_current_time, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_os_trace",
(char*)&sqlite3_os_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_malloc_id",
(char*)&sqlite3_malloc_id, TCL_LINK_STRING);
#if OS_WIN
Tcl_LinkVar(interp, "sqlite_os_type",
(char*)&sqlite3_os_type, TCL_LINK_INT);

View File

@ -199,7 +199,7 @@ void sqlite3FinishTrigger(
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
if( pParse->nErr || pTrig==0 ) goto triggerfinish_cleanup;
if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
pTrig->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = pTrig;
@ -312,7 +312,10 @@ static void sqlitePersistTriggerStep(TriggerStep *p){
*/
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
if( pTriggerStep==0 ) {
sqlite3SelectDelete(pSelect);
return 0;
}
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;

View File

@ -14,42 +14,175 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.149 2005/12/06 12:53:01 danielk1977 Exp $
** $Id: util.c,v 1.150 2005/12/09 14:25:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>
#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
#include <execinfo.h>
void print_stack_trace(){
void *bt[30];
int i;
int n = backtrace(bt, 30);
fprintf(stderr, "STACK: ");
for(i=0; i<n;i++){
fprintf(stderr, "%p ", bt[i]);
}
fprintf(stderr, "\n");
}
#else
#define print_stack_trace()
#endif
#if 0
/*
** If malloc() ever fails, this global variable gets set to 1.
** This causes the library to abort and never again function.
** MALLOC WRAPPER ARCHITECTURE
**
** The sqlite code accesses dynamic memory allocation/deallocation by invoking
** the following four APIs (which may be implemented as macros).
**
** sqlite3Malloc()
** sqlite3MallocRaw()
** sqlite3Realloc()
** sqlite3ReallocOrFree()
** sqlite3Free()
**
** The function sqlite3FreeX performs the same task as sqlite3Free and is
** guaranteed to be a real function.
**
** The above APIs are implemented in terms of the functions provided at the Os
** level (not in this file). The Os level interface is never accessed directly
** by code outside of this file.
**
** sqlite3OsMalloc()
** sqlite3OsRealloc()
** sqlite3OsFree()
** sqlite3OsAllocationSize()
**
** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke
** sqlite3_release_memory() if a call to sqlite3OsMalloc() or
** sqlite3OsRealloc() fails. Function sqlite3Malloc() usually invokes
** sqlite3MallocRaw().
**
** MALLOC TEST WRAPPER ARCHITECTURE
**
** The test wrapper provides extra test facilities to ensure the library
** does not leak memory and handles the failure of the underlying (Os level)
** allocation system correctly. It is only present if the library is
** compiled with the SQLITE_MEMDEBUG macro set.
**
** * Guardposts to detect overwrites.
** * Ability to cause a specific Malloc() or Realloc() to fail.
** * Audit outstanding memory allocations (i.e check for leaks).
*/
int sqlite3Tsd()->mallocFailed = 0;
#endif
/*
** If SQLITE_MEMDEBUG is defined, then use versions of malloc() and
** free() that track memory usage and check for buffer overruns.
** sqlite3OsMalloc
** sqlite3OsRealloc
** sqlite3OsOsFree
** sqlite3OsAllocationSize
**
** Implementation of the os level dynamic memory allocation interface in terms
** of the standard malloc(), realloc() and free() found in many operating
** systems. No rocket science here.
*/
void *sqlite3OsMalloc(int n){
char *p = (char *)malloc(n+8);
assert(n>0);
assert(sizeof(int)<=8);
if( p ){
*(int *)p = n;
}
return (void *)(p + 8);
}
void *sqlite3OsRealloc(void *p, int n){
char *p2 = ((char *)p - 8);
assert(n>0);
p2 = realloc(p2, n+8);
if( p2 ){
*(int *)p2 = n;
}
return (void *)((char *)p2 + 8);
}
void sqlite3OsFree(void *p){
assert(p);
free((void *)((char *)p - 8));
}
int sqlite3OsAllocationSize(void *p){
return *(int *)((char *)p - 8);
}
/*
** TODO!
*/
#define sqlite3_release_memory(x) 0
#ifdef SQLITE_MEMDEBUG
/*--------------------------------------------------------------------------
** Begin code for memory allocation system test layer.
**
** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro.
*/
/* Figure out whether or not to store backtrace() information for each malloc.
** The backtrace() function is only used if SQLITE_MEMDEBUG is set to 2 or
** greater and glibc is in use. If we don't want to use backtrace(), then just
** define it as an empty macro and set the amount of space reserved to 0.
*/
#if defined(__GLIBC__) && SQLITE_MEMDEBUG>1
extern int backtrace(void **, int);
#define TESTALLOC_STACKSIZE 128
#define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
#else
#define backtrace(x, y) 0
#define TESTALLOC_STACKSIZE 0
#define TESTALLOC_STACKFRAMES 0
#endif
/*
** Number of 32-bit guard words. This should probably be a multiple of
** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
** to be 8-byte aligned.
*/
#define TESTALLOC_NGUARD 2
/*
** Size reserved for storing file-name along with each malloc()ed blob.
*/
#define TESTALLOC_FILESIZE 64
/*
** Size reserved for storing the user string.
*/
#define TESTALLOC_USERSIZE 64
const char *sqlite3_malloc_id = 0;
/*
** Blocks used by the test layer have the following format:
**
** <sizeof(void *) pNext pointer>
** <sizeof(void *) pPrev pointer>
** <TESTALLOC_NGUARD 32-bit guard words>
** <The application level allocation>
** <TESTALLOC_NGUARD 32-bit guard words>
** <32-bit line number>
** <TESTALLOC_FILESIZE bytes containing null-terminated file name>
** <TESTALLOC_STACKSIZE bytes of backtrace() output>
*/
#define TESTALLOC_OFFSET_GUARD1(p) (sizeof(void *) * 2)
#define TESTALLOC_OFFSET_DATA(p) ( \
TESTALLOC_OFFSET_GUARD1(p) + sizeof(u32) * TESTALLOC_NGUARD \
)
#define TESTALLOC_OFFSET_GUARD2(p) ( \
TESTALLOC_OFFSET_DATA(p) + sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD \
)
#define TESTALLOC_OFFSET_LINENUMBER(p) ( \
TESTALLOC_OFFSET_GUARD2(p) + sizeof(u32) * TESTALLOC_NGUARD \
)
#define TESTALLOC_OFFSET_FILENAME(p) ( \
TESTALLOC_OFFSET_LINENUMBER(p) + sizeof(u32) \
)
#define TESTALLOC_OFFSET_USER(p) ( \
TESTALLOC_OFFSET_FILENAME(p) + TESTALLOC_FILESIZE \
)
#define TESTALLOC_OFFSET_STACK(p) ( \
TESTALLOC_OFFSET_USER(p) + TESTALLOC_USERSIZE + 8 - \
(TESTALLOC_OFFSET_USER(p) % 8) \
)
#define TESTALLOC_OVERHEAD ( \
sizeof(void *)*2 + /* pPrev and pNext pointers */ \
TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \
sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \
TESTALLOC_USERSIZE + /* User string */ \
TESTALLOC_STACKSIZE /* backtrace() stack */ \
)
/*
** For keeping track of the number of mallocs and frees. This
@ -60,35 +193,25 @@ int sqlite3Tsd()->mallocFailed = 0;
*/
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
int sqlite3_nFree; /* Number of sqliteFree() calls */
int sqlite3_memUsed; /* Total memory obtained from malloc */
int sqlite3_memMax; /* Mem usage high-water mark */
int sqlite3_memUsed; /* TODO Total memory obtained from malloc */
int sqlite3_memMax; /* TODO Mem usage high-water mark */
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
#if SQLITE_MEMDEBUG>1
static int memcnt = 0;
#endif
/*
** Number of 32-bit guard words. This should probably be a multiple of
** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
** to be 8-byte aligned.
*/
#define N_GUARD 2
/*
** Check for a simulated memory allocation failure. Return true if
** the failure should be simulated. Return false to proceed as normal.
*/
static int simulatedMallocFailure(int n, char *zFile, int line){
static int failMalloc(){
SqliteTsd *pTsd = sqlite3Tsd();
if( pTsd->isFail ){
return 1;
}
if( sqlite3_iMallocFail>=0 ){
sqlite3_iMallocFail--;
if( sqlite3_iMallocFail==0 ){
sqlite3Tsd()->mallocFailed++;
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
n, zFile,line);
#endif
sqlite3_iMallocFail = sqlite3_iMallocReset;
pTsd->isFail = 1;
return 1;
}
}
@ -96,303 +219,368 @@ static int simulatedMallocFailure(int n, char *zFile, int line){
}
/*
** Allocate new memory and set it to zero. Return NULL if
** no memory is available.
** The argument is a pointer returned by sqlite3OsMalloc() or Realloc().
** assert() that the first and last (TESTALLOC_NGUARD*4) bytes are set to the
** values set by the applyGuards() function.
*/
void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
void *p;
int *pi;
int i, k;
static void checkGuards(u32 *p)
{
int i;
char *zAlloc = (char *)p;
char *z;
/* Any malloc() calls between a malloc() failure and clearing the
** mallocFailed flag (done before returning control to the user)
** automatically fail. Although this restriction may have to be relaxed in
** the future, for now it makes the system easier to test.
/* First set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
assert(((u32 *)z)[i]==0xdead1122);
}
/* Second set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
u32 guard = 0;
memcpy(&guard, &z[i*sizeof(u32)], sizeof(u32));
assert(guard==0xdead3344);
}
}
/*
** The argument is a pointer returned by sqlite3OsMalloc() or Realloc(). The
** first and last (TESTALLOC_NGUARD*4) bytes are set to known values for use as
** guard-posts.
*/
static void applyGuards(u32 *p)
{
int i;
char *z;
char *zAlloc = (char *)p;
/* First set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
((u32 *)z)[i] = 0xdead1122;
}
/* Second set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
static const int guard = 0xdead3344;
memcpy(&z[i*sizeof(u32)], &guard, sizeof(u32));
}
/* Line number */
z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)]; /* Guard words */
z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
memcpy(z, &sqlite3Tsd()->iLine, sizeof(u32));
/* File name */
z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
strncpy(z, sqlite3Tsd()->zFile, TESTALLOC_FILESIZE);
z[TESTALLOC_FILESIZE - 1] = '\0';
/* User string */
z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
z[0] = 0;
if( sqlite3_malloc_id ){
strncpy(z, sqlite3_malloc_id, TESTALLOC_USERSIZE);
z[TESTALLOC_USERSIZE-1] = 0;
}
/* backtrace() stack */
z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
backtrace((void **)z, TESTALLOC_STACKFRAMES);
/* Sanity check to make sure checkGuards() is working */
checkGuards(p);
}
static void *getOsPointer(void *p)
{
char *z = (char *)p;
return (void *)(&z[-1 * TESTALLOC_OFFSET_DATA(p)]);
}
/*
** The argument points to an Os level allocation. Link it into the threads list
** of allocations.
*/
static void linkAlloc(void *p){
SqliteTsd *pTsd = sqlite3Tsd();
void **pp = (void **)p;
pp[0] = 0;
pp[1] = pTsd->pFirst;
if( pTsd->pFirst ){
((void **)pTsd->pFirst)[0] = p;
}
pTsd->pFirst = p;
}
/*
** The argument points to an Os level allocation. Unlinke it from the threads
** list of allocations.
*/
static void unlinkAlloc(void *p)
{
SqliteTsd *pTsd = sqlite3Tsd();
void **pp = (void **)p;
if( p==pTsd->pFirst ){
assert(!pp[0]);
assert(!pp[1] || ((void **)(pp[1]))[0]==p);
pTsd->pFirst = pp[1];
if( pTsd->pFirst ){
((void **)pTsd->pFirst)[0] = 0;
}
}else{
void **pprev = pp[0];
void **pnext = pp[1];
assert(pprev);
assert(pprev[1]==p);
pprev[1] = (void *)pnext;
if( pnext ){
assert(pnext[0]==p);
pnext[0] = (void *)pprev;
}
}
}
/*
** Pointer p is a pointer to an OS level allocation that has just been
** realloc()ed. Set the list pointers that point to this entry to it's new
** location.
*/
static void relinkAlloc(void *p)
{
void **pp = (void **)p;
if( pp[0] ){
((void **)(pp[0]))[1] = p;
}else{
SqliteTsd *pTsd = sqlite3Tsd();
pTsd->pFirst = p;
}
if( pp[1] ){
((void **)(pp[1]))[0] = p;
}
}
/*
** This function sets the result of the Tcl interpreter passed as an argument
** to a list containing an entry for each currently outstanding call made to
** sqliteMalloc and friends by the current thread.
**
** TODO: This will eventually be done as part of the same wrapper that may
** call sqlite3_release_memory(). Above the sqlite3OsMalloc() level.
** Todo: We could have a version of this function that outputs to stdout,
** to debug memory leaks when Tcl is not available.
*/
if( sqlite3Tsd()->mallocFailed ){
return 0;
#ifdef TCLSH
#include <tcl.h>
int sqlite3OutstandingMallocs(Tcl_Interp *interp){
void *p;
SqliteTsd *pTsd = sqlite3Tsd();
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_IncrRefCount(pRes);
for(p=pTsd->pFirst; p; p=((void **)p)[1]){
Tcl_Obj *pEntry = Tcl_NewObj();
Tcl_Obj *pStack = Tcl_NewObj();
char *z;
u32 iLine;
int nBytes = sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
char *zAlloc = (char *)p;
int i;
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(nBytes));
z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
memcpy(&iLine, z, sizeof(u32));
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(iLine));
z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
for(i=0; i<TESTALLOC_STACKFRAMES; i++){
char zHex[128];
sprintf(zHex, "%p", ((void **)z)[i]);
Tcl_ListObjAppendElement(0, pStack, Tcl_NewStringObj(zHex, -1));
}
if( n==0 ){
return 0;
Tcl_ListObjAppendElement(0, pEntry, pStack);
Tcl_ListObjAppendElement(0, pRes, pEntry);
}
if( simulatedMallocFailure(n, zFile, line) ){
return 0;
}
sqlite3_memUsed += n;
if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
k = (n+sizeof(int)-1)/sizeof(int);
pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
if( pi==0 ){
if( n>0 ) sqlite3Tsd()->mallocFailed++;
return 0;
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, pRes);
Tcl_DecrRefCount(pRes);
return TCL_OK;
}
#endif
/*
** This is the test layer's wrapper around sqlite3OsMalloc().
*/
static void * OSMALLOC(int n){
if( !failMalloc() ){
u32 *p;
p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD);
assert(p);
sqlite3_nMalloc++;
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
pi[N_GUARD] = n;
for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
p = &pi[N_GUARD+1];
memset(p, bZero==0, n);
#if SQLITE_MEMDEBUG>1
print_stack_trace();
fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
++memcnt, n, (int)p, zFile,line);
#endif
return p;
applyGuards(p);
linkAlloc(p);
return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
}
return 0;
}
/*
** This version of malloc is always a real function, never a macro
** This is the test layer's wrapper around sqlite3OsFree(). The argument is a
** pointer to the space allocated for the application to use.
*/
void *sqlite3MallocX(int n){
return sqlite3Malloc_(n, 0, __FILE__, __LINE__);
}
/*
** Check to see if the given pointer was obtained from sqliteMalloc()
** and is able to hold at least N bytes. Raise an exception if this
** is not the case.
**
** This routine is used for testing purposes only.
*/
void sqlite3CheckMemory(void *p, int N){
int *pi = p;
int n, i, k;
pi -= N_GUARD+1;
for(i=0; i<N_GUARD; i++){
assert( pi[i]==0xdead1122 );
}
n = pi[N_GUARD];
assert( N>=0 && N<n );
k = (n+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
assert( pi[k+N_GUARD+1+i]==0xdead3344 );
}
}
/*
** Free memory previously obtained from sqliteMalloc()
*/
void sqlite3Free_(void *p, char *zFile, int line){
if( p ){
int *pi, i, k, n;
pi = p;
pi -= N_GUARD+1;
void OSFREE(void *pFree){
u32 *p = (u32 *)getOsPointer(pFree); /* p points to Os level allocation */
checkGuards(p);
unlinkAlloc(p);
sqlite3OsFree(p);
sqlite3_nFree++;
for(i=0; i<N_GUARD; i++){
if( pi[i]!=0xdead1122 ){
fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
return;
}
}
n = pi[N_GUARD];
sqlite3_memUsed -= n;
k = (n+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
return;
}
}
memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
++memcnt, n, (int)p, zFile,line);
#endif
free(pi);
}
}
/*
** Resize a prior allocation. If p==0, then this routine
** works just like sqliteMalloc(). If n==0, then this routine
** works just like sqliteFree().
** This is the test layer's wrapper around sqlite3OsRealloc().
*/
void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
int *oldPi, *pi, i, k, oldN, oldK;
void *p;
if( oldP==0 ){
return sqlite3Malloc_(n,1,zFile,line);
void * OSREALLOC(void *pRealloc, int n){
if( !failMalloc() ){
u32 *p = (u32 *)getOsPointer(pRealloc);
checkGuards(p);
p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD);
applyGuards(p);
relinkAlloc(p);
return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
}
if( n==0 ){
sqlite3Free_(oldP,zFile,line);
return 0;
}
if( simulatedMallocFailure(n, zFile, line) ){
return 0;
void OSMALLOC_FAILED(){
sqlite3Tsd()->isFail = 0;
}
oldPi = oldP;
oldPi -= N_GUARD+1;
if( oldPi[0]!=0xdead1122 ){
fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
return 0;
}
oldN = oldPi[N_GUARD];
sqlite3_memUsed -= oldN;
oldK = (oldN+sizeof(int)-1)/sizeof(int);
for(i=0; i<N_GUARD; i++){
if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
(int)oldP);
return 0;
}
}
k = (n + sizeof(int) - 1)/sizeof(int);
pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
if( pi==0 ){
if( n>0 ) sqlite3Tsd()->mallocFailed++;
return 0;
}
for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
pi[N_GUARD] = n;
sqlite3_memUsed += n;
if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
p = &pi[N_GUARD+1];
memcpy(p, oldP, n>oldN ? oldN : n);
if( n>oldN ){
memset(&((char*)p)[oldN], 0x55, n-oldN);
}
memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
free(oldPi);
#if SQLITE_MEMDEBUG>1
print_stack_trace();
fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
#else
#define OSMALLOC(x) sqlite3OsMalloc(x)
#define OSREALLOC(x,y) sqlite3OsRealloc(x,y)
#define OSFREE(x) sqlite3OsFree(x)
#define OSMALLOC_FAILED()
#endif
/*
** End code for memory allocation system test layer.
**--------------------------------------------------------------------------*/
/*
** Allocate and return N bytes of uninitialised memory by calling
** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory
** by calling sqlite3_release_memory().
*/
void *sqlite3MallocRaw(int n){
SqliteTsd *pTsd = sqlite3Tsd();
void *p = 0;
if( n>0 && !pTsd->mallocFailed ){
while( !(p = OSMALLOC(n)) && sqlite3_release_memory(n) );
if( !p ){
sqlite3Tsd()->mallocFailed = 1;
OSMALLOC_FAILED();
}
}
return p;
}
/*
** Make a copy of a string in memory obtained from sqliteMalloc()
** Resize the allocation at p to n bytes by calling sqlite3OsRealloc(). The
** pointer to the new allocation is returned. If the Realloc() call fails,
** attempt to free memory by calling sqlite3_release_memory().
*/
char *sqlite3StrDup_(const char *z, char *zFile, int line){
char *zNew;
if( z==0 ) return 0;
zNew = sqlite3Malloc_(strlen(z)+1, 0, zFile, line);
if( zNew ) strcpy(zNew, z);
return zNew;
void *sqlite3Realloc(void *p, int n){
SqliteTsd *pTsd = sqlite3Tsd();
if( pTsd->mallocFailed ){
return 0;
}
char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
char *zNew;
if( z==0 ) return 0;
zNew = sqlite3Malloc_(n+1, 0, zFile, line);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
if( !p ){
return sqlite3Malloc(n);
}else{
void *np = 0;
while( !(np = OSREALLOC(p, n)) && sqlite3_release_memory(n) );
if( !np ){
pTsd->mallocFailed = 1;
OSMALLOC_FAILED();
}
return np;
}
return zNew;
}
/*
** A version of sqliteFree that is always a function, not a macro.
** Free the memory pointed to by p. p must be either a NULL pointer or a
** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc().
*/
void sqlite3FreeX(void *p){
sqliteFree(p);
if( p ){
OSFREE(p);
}
}
#endif /* SQLITE_MEMDEBUG */
/*
** The following versions of malloc() and free() are for use in a
** normal build.
** A version of sqliteMalloc() that is always a function, not a macro.
** Currently, this is used only to alloc only used drawback.
*/
#if !defined(SQLITE_MEMDEBUG)
void *sqlite3MallocX(int n){
return sqliteMalloc(n);
}
/*
** Allocate new memory and set it to zero. Return NULL if
** no memory is available. See also sqliteMallocRaw().
** sqlite3Malloc
** sqlite3ReallocOrFree
**
** These two are implemented as wrappers around sqlite3MallocRaw(),
** sqlite3Realloc() and sqlite3Free().
*/
void *sqlite3Malloc(int n){
void *p;
if( n==0 ) return 0;
if( (p = malloc(n))==0 ){
if( n>0 ) sqlite3Tsd()->mallocFailed++;
}else{
void *p = sqlite3MallocRaw(n);
if( p ){
memset(p, 0, n);
}
return p;
}
/*
** Allocate new memory but do not set it to zero. Return NULL if
** no memory is available. See also sqliteMalloc().
*/
void *sqlite3MallocRaw(int n){
void *p;
if( n==0 ) return 0;
if( (p = malloc(n))==0 ){
if( n>0 ) sqlite3Tsd()->mallocFailed++;
void sqlite3ReallocOrFree(void **pp, int n){
void *p = sqlite3Realloc(*pp, n);
if( !p ){
sqlite3FreeX(*pp);
}
return p;
*pp = p;
}
/*
** Free memory previously obtained from sqliteMalloc()
*/
void sqlite3FreeX(void *p){
if( p ){
free(p);
}
}
/*
** Resize a prior allocation. If p==0, then this routine
** works just like sqliteMalloc(). If n==0, then this routine
** works just like sqliteFree().
*/
void *sqlite3Realloc(void *p, int n){
void *p2;
if( p==0 ){
return sqliteMalloc(n);
}
if( n==0 ){
sqliteFree(p);
return 0;
}
p2 = realloc(p, n);
if( p2==0 ){
if( n>0 ) sqlite3Tsd()->mallocFailed++;
}
return p2;
}
/*
** Make a copy of a string in memory obtained from sqliteMalloc()
** Make a copy of a string in memory obtained from sqliteMalloc(). These
** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
** is because when memory debugging is turned on, these two functions are
** called via macros that record the current file and line number in the
** SqliteTsd structure.
*/
char *sqlite3StrDup(const char *z){
char *zNew;
if( z==0 ) return 0;
zNew = sqliteMallocRaw(strlen(z)+1);
zNew = sqlite3MallocRaw(strlen(z)+1);
if( zNew ) strcpy(zNew, z);
return zNew;
}
char *sqlite3StrNDup(const char *z, int n){
char *zNew;
if( z==0 ) return 0;
zNew = sqliteMallocRaw(n+1);
zNew = sqlite3MallocRaw(n+1);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
#endif /* !defined(SQLITE_MEMDEBUG) */
/*
** Reallocate a buffer to a different size. This is similar to
** sqliteRealloc() except that if the allocation fails the buffer
** is freed.
*/
void sqlite3ReallocOrFree(void **ppBuf, int newSize){
void *pNew = sqliteRealloc(*ppBuf, newSize);
if( pNew==0 ){
sqliteFree(*ppBuf);
}
*ppBuf = pNew;
}
/*
** Create a string from the 2nd and subsequent arguments (up to the
@ -426,11 +614,6 @@ void sqlite3SetString(char **pz, ...){
zResult += strlen(zResult);
}
va_end(ap);
#ifdef SQLITE_MEMDEBUG
#if SQLITE_MEMDEBUG>1
fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
#endif
#endif
}
/*
@ -1026,14 +1209,44 @@ void *sqlite3TextToPtr(const char *z){
/*
** Return a pointer to the SqliteTsd associated with the calling thread.
*/
static SqliteTsd tsd = { 0 };
static SqliteTsd tsd = {
0 /* mallocFailed flag */
#ifndef NDEBUG
, 1 /* mallocAllowed flag */
#endif
#ifndef SQLITE_MEMDEBUG
, 0
, 0
, 0
, 0
#endif
};
SqliteTsd *sqlite3Tsd(){
return &tsd;
}
void sqlite3ClearMallocFailed(){
void sqlite3MallocClearFailed(){
sqlite3Tsd()->mallocFailed = 0;
}
#ifndef NDEBUG
/*
** This function sets a flag in the thread-specific-data structure that will
** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called.
*/
void sqlite3MallocDisallow(){
assert(sqlite3Tsd()->mallocAllowed);
sqlite3Tsd()->mallocAllowed = 0;
}
/*
** This function clears the flag set in the thread-specific-data structure set
** by sqlite3MallocDisallow().
*/
void sqlite3MallocAllow(){
assert(!sqlite3Tsd()->mallocAllowed);
sqlite3Tsd()->mallocAllowed = 1;
}
#endif

View File

@ -14,7 +14,7 @@
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.51 2005/12/06 17:48:32 danielk1977 Exp $
** $Id: vacuum.c,v 1.52 2005/12/09 14:25:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@ -311,12 +311,17 @@ end_of_vacuum:
db->autoCommit = 1;
if( pDetach ){
int mf = sqlite3Tsd()->mallocFailed;
sqlite3Tsd()->mallocFailed = 0;
sqlite3MallocDisallow();
((Vdbe *)pDetach)->expired = 0;
sqlite3_step(pDetach);
rc2 = sqlite3_finalize(pDetach);
if( rc==SQLITE_OK ){
rc = rc2;
}
sqlite3MallocAllow();
sqlite3Tsd()->mallocFailed = mf;
}
/* If one of the execSql() calls above returned SQLITE_NOMEM, then the

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.502 2005/12/06 12:53:01 danielk1977 Exp $
** $Id: vdbe.c,v 1.503 2005/12/09 14:25:09 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -390,11 +390,15 @@ int sqlite3VdbeExec(
if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
assert( db->magic==SQLITE_MAGIC_BUSY );
pTos = p->pTos;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
goto no_mem;
}
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
p->rc = SQLITE_OK;
assert( p->explain==0 );
pTos = p->pTos;
if( sqlite3Tsd()->mallocFailed ) goto no_mem;
if( p->popStack ){
popStack(&pTos, p->popStack);
p->popStack = 0;
@ -3898,13 +3902,13 @@ case OP_ParseSchema: { /* no-push */
db->init.busy = 1;
assert(0==sqlite3Tsd()->mallocFailed);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
sqliteFree(zSql);
db->init.busy = 0;
sqlite3SafetyOn(db);
if( rc==SQLITE_NOMEM ){
sqlite3Tsd()->mallocFailed = 1;
goto no_mem;
}
sqliteFree(zSql);
break;
}

View File

@ -241,7 +241,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
#endif
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
sqlite3ClearMallocFailed();
sqlite3MallocClearFailed();
return rc;
}
@ -378,30 +378,78 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
return &pVm->pTos[(1-vals)+i];
}
/*
** This function is called after invoking an sqlite3_value_XXX function on a
** column value (i.e. a value returned by evaluating an SQL expression in the
** select list of a SELECT statement) that may cause a malloc() failure. If
** malloc() has failed, the threads mallocFailed flag is cleared and the result
** code of statement pStmt set to SQLITE_NOMEM.
**
** Specificly, this is called from within:
**
** sqlite3_column_int()
** sqlite3_column_int64()
** sqlite3_column_text()
** sqlite3_column_text16()
** sqlite3_column_real()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
**
** But not for sqlite3_column_blob(), which never calls malloc().
*/
static void columnMallocFailure(sqlite3_stmt *pStmt)
{
/* If malloc() failed during an encoding conversion within an
** sqlite3_column_XXX API, then set the return code of the statement to
** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR
** and _finalize() will return NOMEM.
*/
if( sqlite3Tsd()->mallocFailed ){
((Vdbe *)pStmt)->rc = SQLITE_NOMEM;
sqlite3MallocClearFailed();
}
}
/**************************** sqlite3_column_ *******************************
** The following routines are used to access elements of the current row
** in the result set.
*/
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
return sqlite3_value_blob( columnMem(pStmt,i) );
const void *val;
sqlite3MallocDisallow();
val = sqlite3_value_blob( columnMem(pStmt,i) );
sqlite3MallocAllow();
return val;
}
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
return sqlite3_value_bytes( columnMem(pStmt,i) );
int val = sqlite3_value_bytes( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
return sqlite3_value_bytes16( columnMem(pStmt,i) );
int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
return sqlite3_value_double( columnMem(pStmt,i) );
double val = sqlite3_value_double( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
return sqlite3_value_int( columnMem(pStmt,i) );
int val = sqlite3_value_int( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
return sqlite3_value_int64( columnMem(pStmt,i) );
sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text( columnMem(pStmt,i) );
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
#if 0
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
@ -410,7 +458,9 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
#endif
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
return sqlite3_value_text16( columnMem(pStmt,i) );
const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
@ -452,11 +502,10 @@ static const void *columnName(
/* A malloc may have failed inside of the xFunc() call. If this is the case,
** clear the mallocFailed flag and return NULL.
*/
sqlite3ClearMallocFailed();
sqlite3MallocClearFailed();
return ret;
}
/*
** Return the name of the Nth column of the result set returned by SQL
** statement pStmt.

View File

@ -415,7 +415,7 @@ static void freeP3(int p3type, void *p3){
void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
Op *pOp;
assert( p->magic==VDBE_MAGIC_INIT );
if( p==0 || p->aOp==0 ){
if( p==0 || p->aOp==0 || sqlite3Tsd()->mallocFailed ){
if (n != P3_KEYINFO) {
freeP3(n, (void*)*(char**)&zP3);
}
@ -470,7 +470,7 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
va_list ap;
assert( p->nOp>0 );
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 );
assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || sqlite3Tsd()->mallocFailed );
va_start(ap, zFormat);
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
va_end(ap);

View File

@ -13,7 +13,7 @@
# correctly. The emphasis of these tests are the _prepare(), _step() and
# _finalize() calls.
#
# $Id: malloc3.test,v 1.3 2005/12/07 06:27:45 danielk1977 Exp $
# $Id: malloc3.test,v 1.4 2005/12/09 14:25:12 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -580,14 +580,19 @@ proc run_test {arglist {pcstart 0} {iFailStart 1}} {
default { error "Unknown switch: $k" }
}
# if {$iFail > ($iFailStart+1)} return
}
}
# Turn of the Tcl interface's prepared statement caching facility.
db cache size 0
#run_test $::run_test_script 59 97
run_test $::run_test_script
# run_test [lrange $::run_test_script 0 3] 0 63
sqlite_malloc_fail 0
db close
pp_check_for_leaks
finish_test

View File

@ -12,11 +12,15 @@
# This file contains tests to ensure that the library handles malloc() failures
# correctly. The emphasis in this file is on sqlite3_column_XXX() APIs.
#
# $Id: malloc4.test,v 1.1 2005/12/07 06:27:45 danielk1977 Exp $
# $Id: malloc4.test,v 1.2 2005/12/09 14:25:12 danielk1977 Exp $
#---------------------------------------------------------------------------
# NOTES ON EXPECTED BEHAVIOUR
#
# [193] When a memory allocation failure occurs during sqlite3_column_name(),
# sqlite3_column_name16(), sqlite3_column_decltype(), or
# sqlite3_column_decltype16() the function shall return NULL.
#
#---------------------------------------------------------------------------
set testdir [file dirname $argv0]
@ -29,7 +33,6 @@ if {[info command sqlite_malloc_stat]==""} {
return
}
proc do_stmt_test {id sql} {
set ::sql $sql
set go 1
@ -48,6 +51,18 @@ proc do_stmt_test {id sql} {
# Test malloc failure in the _name(), _name16(), decltype() and
# decltype16() APIs. Calls that occur after the malloc() failure should
# return NULL. No error is raised though.
#
# ${testid}.2.1 - Call _name()
# ${testid}.2.2 - Call _name16()
# ${testid}.2.3 - Call _name()
# ${testid}.2.4 - Check that the return values of the above three calls are
# consistent with each other and with the simulated
# malloc() failures.
#
# Because the code that implements the _decltype() and _decltype16() APIs
# is the same as the _name() and _name16() implementations, we don't worry
# about explicitly testing them.
#
do_test ${testid}.2.1 {
set mf1 [expr [lindex [sqlite_malloc_stat] 2] <= 0]
set ::name8 [sqlite3_column_name $::STMT 0]
@ -78,27 +93,83 @@ proc do_stmt_test {id sql} {
}
} {1}
if {$::mallocFailed == 0} {
# Step the statement so that we can call _text() and _text16(). Before
# running sqlite3_step(), make sure that malloc() is not about to fail.
# Memory allocation failures that occur within sqlite3_step() are tested
# elsewhere.
set mf [lindex [sqlite_malloc_stat] 2]
sqlite_malloc_fail 0
do_test ${testid}.3 {
sqlite3_step $::STMT
} {SQLITE_ROW}
sqlite_malloc_fail $mf
# Test for malloc() failures within _text() and _text16().
#
do_test ${testid}.4.1 {
set ::text8 [sqlite3_column_text $::STMT 0]
set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed]
expr {$mf==0 || $::text8 == ""}
} {1}
do_test ${testid}.4.2 {
set ::text16 [sqlite3_column_text16 $::STMT 0]
set ::text16 [encoding convertfrom unicode $::text16]
set ::text16 [string range $::text16 0 end-1]
set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed]
expr {$mf==0 || $::text16 == ""}
} {1}
do_test ${testid}.4.3 {
set ::text8_2 [sqlite3_column_text $::STMT 0]
set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed]
expr {$mf==0 || $::text8_2 == "" || ($::text16 == "" && $::text8 != "")}
} {1}
# Test for malloc() failures within _int(), _int64() and _real(). The only
# way this can occur is if the string has to be translated from UTF-16 to
# UTF-8 before being converted to a numeric value.
do_test ${testid}.4.4.1 {
set mf [lindex [sqlite_malloc_stat] 2]
sqlite_malloc_fail 0
sqlite3_column_text16 $::STMT 0
sqlite_malloc_fail $mf
sqlite3_column_int $::STMT 0
} {0}
do_test ${testid}.4.5 {
set mf [lindex [sqlite_malloc_stat] 2]
sqlite_malloc_fail 0
sqlite3_column_text16 $::STMT 0
sqlite_malloc_fail $mf
sqlite3_column_int64 $::STMT 0
} {0}
do_test ${testid}.4.6 {
set mf [lindex [sqlite_malloc_stat] 2]
sqlite_malloc_fail 0
sqlite3_column_text16 $::STMT 0
sqlite_malloc_fail $mf
sqlite3_column_double $::STMT 0
} {0.0}
set mallocFailedAfterStep [expr \
[lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed
]
sqlite_malloc_fail 0
# Test that if a malloc() failed the next call to sqlite3_step() returns
# SQLITE_ERROR. If malloc() did not fail, it should return SQLITE_DONE.
#
do_test ${testid}.5 {
sqlite3_step $::STMT
} [expr {$mallocFailedAfterStep ? "SQLITE_ERROR" : "SQLITE_DONE"}]
do_test ${testid}.6 {
sqlite3_finalize $::STMT
} [expr {$mallocFailedAfterStep ? "SQLITE_NOMEM" : "SQLITE_OK"}]
if {$::mallocFailed == 0 && $mallocFailedAfterStep == 0} {
sqlite_malloc_fail 0
set go 0
}
if 0 {
# Test that if a malloc() failed the next call to sqlite3_step() returns
# SQLITE_ERROR. If malloc() did not fail, it should return SQLITE_ROW.
#
# Before running sqlite3_step(), make sure that malloc() is not about to
# fail. Memory allocation failures that occur within sqlite3_step() are
# tested elsewhere.
do_test ${testid}.3 {
set rc [sqlite3_step $::STMT]
list [expr $rc=="SQLITE_ERROR"] [expr $rc=="SQLITE_ROW"]
} [list $mallocFailed [expr !$mallocFailed]]
}
do_test ${testid}.4 {
sqlite3_finalize $::STMT
} {SQLITE_OK}
}
}
@ -106,7 +177,11 @@ execsql {
CREATE TABLE tbl(
the_first_reasonably_long_column_name that_also_has_quite_a_lengthy_type
);
INSERT INTO tbl VALUES(
'An extra long string. Far too long to be stored in NBFS bytes.'
);
}
do_stmt_test 1 "SELECT * FROM tbl"
sqlite_malloc_fail 0

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement.
#
# $Id: select1.test,v 1.43 2005/09/08 10:37:01 drh Exp $
# $Id: select1.test,v 1.44 2005/12/09 14:25:12 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -799,5 +799,4 @@ ifcapable {compound && subquery} {
} {x 1 x 3}
} ;# ifcapable compound
finish_test

View File

@ -11,7 +11,7 @@
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.52 2005/11/26 00:25:04 drh Exp $
# $Id: tester.tcl,v 1.53 2005/12/09 14:25:12 danielk1977 Exp $
# Make sure tclsqlite3 was compiled correctly. Abort now with an
# error message if not.
@ -83,6 +83,7 @@ set maxErr 1000
#
proc do_test {name cmd expected} {
global argv nErr nTest skip_test maxErr
set ::sqlite_malloc_id $name
if {$skip_test} {
set skip_test 0
return
@ -139,7 +140,13 @@ proc finish_test {} {
proc finalize_testing {} {
global nTest nErr nProb sqlite_open_file_count
if {$nErr==0} memleak_check
catch {db close}
catch {db2 close}
catch {db3 close}
pp_check_for_leaks
puts "$nErr errors out of $nTest tests"
puts "Failures on these tests: $::failList"
if {$nProb>0} {
@ -423,6 +430,59 @@ proc copy_file {from to} {
}
}
# This command checks for outstanding calls to sqliteMalloc() from within
# the current thread. A list is returned with one entry for each outstanding
# malloc. Each list entry is itself a list of 5 items, as follows:
#
# { <number-bytes> <file-name> <line-number> <test-case> <stack-dump> }
#
proc check_for_leaks {} {
set ret [list]
foreach alloc [sqlite_malloc_outstanding] {
foreach {nBytes file iLine userstring backtrace} $alloc {}
set stack [list]
set skip 0
# The first command in this block will probably fail on windows. This
# means there will be no stack dump available.
catch {
set stuff [eval "exec addr2line -e ./testfixture -f $backtrace"]
foreach {func line} $stuff {
if {$func != "??" || $line != "??:0"} {
regexp {.*/(.*)} $line dummy line
lappend stack "${func}() $line"
} else {
if {[lindex $stack end] != "..."} {
lappend stack "..."
}
}
}
}
if {!$skip} {
lappend ret [list $nBytes $file $iLine $userstring $stack]
}
}
return $ret
}
# Pretty print a report based on the return value of [check_for_leaks] to
# stdout.
proc pp_check_for_leaks {} {
set l [check_for_leaks]
set n 0
foreach leak $l {
foreach {nBytes file iLine userstring stack} $leak {}
puts "$nBytes bytes leaked at $file:$iLine ($userstring)"
foreach frame $stack {
puts " $frame"
}
incr n $nBytes
}
puts "Memory leaked: $n bytes in [llength $l] allocations"
puts ""
}
# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)