diff --git a/manifest b/manifest index a4a5c34e91..71f5116089 100644 --- a/manifest +++ b/manifest @@ -1,28 +1,28 @@ -C :-)\s(CVS\s79) -D 2000-06-08T11:25:01 +C remove\sall\smemory\sleaks\s(CVS\s80) +D 2000-06-08T13:36:40 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in 17ba1ccf8d2d40c627796bba8f72952365d6d644 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 -F src/build.c 5e3b6bab5604cd99019ea6d58f9166d879476991 +F src/build.c 925a785da2758269cb8773691e157ea5269178ba F src/dbbe.c 9b191b16ff01ec5bc0af436558501d07938ba4f0 F src/dbbe.h a8a46f71238e0f09f3ec08fd9d1c8c7f4cdc49bf F src/delete.c c267b93f7ccb5493b677fa18201880267c699aa8 -F src/expr.c ab419c2f09529c8c518484b7f9af68b79e481064 +F src/expr.c 8c79de4d19081fe81765dac47bd496c32b606369 F src/insert.c ac4edfff474589c00b2490f206317dc5822122e5 F src/main.c e3297835b8e38ca726ac73f2c2bdb7cf08103197 -F src/parse.y bb2126c8313c111184b89af8675911dcb57f1dca -F src/select.c d0b54f5f5a2bb6cd5aebc24c192dea4d4dbaeb84 +F src/parse.y e6c61f20620b4a331fecb5217eb556ac41aa441c +F src/select.c b1ffe8e6a03540f690c3749c9c12257fca3463bc F src/shell.c 3f4afc39a36e4824e8aa262623fd03568874799e F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268 -F src/sqliteInt.h 816c491f9896090dde03804fd3f60346456b99df +F src/sqliteInt.h 0aac58ed2e9fe46f24411e2e012fe85cd3457129 F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7 -F src/tokenize.c 900af9479d0feaa76b0225680196aa81afec930a +F src/tokenize.c cb9eacd12548ee1ae7089eb3177b38851d7f0a1f F src/update.c d8d90df714bac99c68446a0c49f3d957ca6fc3c8 -F src/util.c 33f9baa01e45394ef0cf85361a0e872987884315 -F src/vdbe.c 0ce44df13c97472686b376cc93cca5f40079878d +F src/util.c 38e4bb5edf6fa92e677698c45785bf73c69b9e9f +F src/vdbe.c 37f3b0824f90bfe3001dcf337bafb982f9d1b025 F src/vdbe.h 8f79f57c66ce1030f6371ff067b326d627a52c6d F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 @@ -43,12 +43,13 @@ F test/select5.test b6f8b6bef467764a3edaea4e7cb9b0eb8f02ccd8 F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5 F test/table.test 85d6f410d127ec508c6640f02d7c40d218414e81 -F test/tester.tcl 44690d463c1dc83a4c76ccde07cc146a988600f6 +F test/tester.tcl 95b286791e6256bb6db0165f9342c70fff549a62 F test/update.test 69459302ea75cafac1479e60b0e36efb88123c0e F test/vacuum.test 8becf5cfeb897108b35cdd996793e7f1df2f28fd F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b F tool/lemon.c 1f0e96515c12e9e413f5b8fdebc79ddcf18ddc9d F tool/lempar.c a1eec94d6eacc12332368660ec65f3b248853833 +F tool/memleak.awk a0a11dd84bf4582acc81c3c61271021ae49b3f15 F tool/opNames.awk 2bd9071a138e4e2be13dc98fe066398a61219e1e F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9 @@ -56,7 +57,7 @@ F www/c_interface.tcl 9ac800854272db5fe439e07b7435b243a5422293 F www/changes.tcl 04e66b4257589ff78a7e1de93e9dda4725fb03d6 F www/index.tcl 52e29a4eeda8d59e91af43c61fef177c5f2ffd53 F www/sqlite.tcl 2f933ce18cffd34a0a020a82435ab937137970fd -P 923c14fe120c7d5470a18257659154c4f98226b7 -R 57bfb2e9c02ed1359339dbb2f56b538b +P 305b043f4f71278d6d2c32e6e457f63efefae20d +R 2e8cf1a074c330c6453a374880c3eab1 U drh -Z d5e2038c5fa3d3fb8e65d77ade627b18 +Z f0a43ffe3166fea312bf9330021c453e diff --git a/manifest.uuid b/manifest.uuid index 799644c392..58b0a76d00 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -305b043f4f71278d6d2c32e6e457f63efefae20d \ No newline at end of file +bf98cf82a73c54c4eced04994bb1a019844dfc03 \ No newline at end of file diff --git a/src/build.c b/src/build.c index ad6113e75b..692b61a418 100644 --- a/src/build.c +++ b/src/build.c @@ -33,7 +33,7 @@ ** COPY ** VACUUM ** -** $Id: build.c,v 1.16 2000/06/07 23:51:50 drh Exp $ +** $Id: build.c,v 1.17 2000/06/08 13:36:40 drh Exp $ */ #include "sqliteInt.h" @@ -191,6 +191,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){ pNext = pIndex->pNext; sqliteDeleteIndex(db, pIndex); } + sqliteFree(pTable->zName); sqliteFree(pTable->aCol); sqliteFree(pTable); } @@ -202,8 +203,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){ ** be freed by the calling function. */ char *sqliteTableNameFromToken(Token *pName){ - char *zName = 0; - sqliteSetNString(&zName, pName->z, pName->n, 0); + char *zName = sqliteStrNDup(pName->z, pName->n); sqliteDequote(zName); return zName; } diff --git a/src/expr.c b/src/expr.c index 54840b07d8..a3200eb4d9 100644 --- a/src/expr.c +++ b/src/expr.c @@ -23,7 +23,7 @@ ************************************************************************* ** This file contains C code routines used for processing expressions ** -** $Id: expr.c,v 1.12 2000/06/08 11:25:01 drh Exp $ +** $Id: expr.c,v 1.13 2000/06/08 13:36:40 drh Exp $ */ #include "sqliteInt.h" @@ -118,8 +118,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ case TK_ID: { int cnt = 0; /* Number of matches */ int i; /* Loop counter */ - char *z = 0; - sqliteSetNString(&z, pExpr->token.z, pExpr->token.n, 0); + char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n); for(i=0; inId; i++){ int j; Table *pTab = pTabList->a[i].pTab; @@ -159,10 +158,8 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ pRight = pExpr->pRight; assert( pLeft && pLeft->op==TK_ID ); assert( pRight && pRight->op==TK_ID ); - zLeft = 0; - sqliteSetNString(&zLeft, pLeft->token.z, pLeft->token.n, 0); - zRight = 0; - sqliteSetNString(&zRight, pRight->token.z, pRight->token.n, 0); + zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n); + zRight = sqliteStrNDup(pRight->token.z, pRight->token.n); for(i=0; inId; i++){ int j; char *zTab; @@ -512,8 +509,23 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ sqliteVdbeAddOp(v, OP_AddImm, -1, 0, 0, 0); break; } - case TK_NOT: case TK_UMINUS: { + assert( pExpr->pLeft ); + if( pExpr->pLeft->op==TK_INTEGER ){ + int i = atoi(pExpr->pLeft->token.z); + sqliteVdbeAddOp(v, OP_Integer, -i, 0, 0, 0); + break; + }else if( pExpr->pLeft->op==TK_FLOAT ){ + Token *p = &pExpr->pLeft->token; + char *z = sqliteMalloc( p->n + 2 ); + sprintf(z, "-%.*s", p->n, p->z); + sqliteVdbeAddOp(v, OP_String, 0, 0, z, 0); + sqliteFree(z); + break; + } + /* Fall true into TK_NOT */ + } + case TK_NOT: { sqliteExprCode(pParse, pExpr->pLeft); sqliteVdbeAddOp(v, op, 0, 0, 0, 0); break; diff --git a/src/parse.y b/src/parse.y index 864bce4cff..5b58983021 100644 --- a/src/parse.y +++ b/src/parse.y @@ -26,7 +26,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.16 2000/06/07 23:51:50 drh Exp $ +** @(#) $Id: parse.y,v 1.17 2000/06/08 13:36:40 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -271,16 +271,14 @@ itemlist(A) ::= item(X). {A = sqliteExprListAppend(0,X,0);} item(A) ::= INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);} item(A) ::= PLUS INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);} item(A) ::= MINUS INTEGER(X). { - A = sqliteExpr(TK_INTEGER, 0, 0, 0); - A->token.z = 0; - sqliteSetNString(&A->token.z, "-", 1, X.z, X.n, 0); + A = sqliteExpr(TK_UMINUS, 0, 0, 0); + A->pLeft = sqliteExpr(TK_INTEGER, 0, 0, &X); } item(A) ::= FLOAT(X). {A = sqliteExpr(TK_FLOAT, 0, 0, &X);} item(A) ::= PLUS FLOAT(X). {A = sqliteExpr(TK_FLOAT, 0, 0, &X);} item(A) ::= MINUS FLOAT(X). { - A = sqliteExpr(TK_FLOAT, 0, 0, 0); - A->token.z = 0; - sqliteSetNString(&A->token.z, "-", 1, X.z, X.n, 0); + A = sqliteExpr(TK_UMINUS, 0, 0, 0); + A->pLeft = sqliteExpr(TK_FLOAT, 0, 0, &X); } item(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);} item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);} diff --git a/src/select.c b/src/select.c index 0aa76ff011..58b35ce1a7 100644 --- a/src/select.c +++ b/src/select.c @@ -24,7 +24,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements. ** -** $Id: select.c,v 1.21 2000/06/08 11:25:01 drh Exp $ +** $Id: select.c,v 1.22 2000/06/08 13:36:40 drh Exp $ */ #include "sqliteInt.h" @@ -144,6 +144,7 @@ static int selectInnerLoop( } zSortOrder[pOrderBy->nExpr] = 0; sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, 0); + sqliteFree(zSortOrder); sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0); }else @@ -378,12 +379,12 @@ static int matchOrderbyToColumn( for(j=0; jnExpr; j++){ if( pEList->a[i].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){ char *zName = pEList->a[i].zName; - char *zLabel = 0; - sqliteSetNString(&zLabel, pE->token.z, pE->token.n, 0); + char *zLabel = sqliteStrNDup(pE->token.z, pE->token.n); sqliteDequote(zLabel); if( sqliteStrICmp(zName, zLabel)==0 ){ match = 1; } + sqliteFree(zLabel); } if( match==0 && sqliteExprCompare(pE, pEList->a[i].pExpr) ){ match = 1; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a4530ce79b..eec9e4b861 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -23,7 +23,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.22 2000/06/07 23:51:51 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.23 2000/06/08 13:36:40 drh Exp $ */ #include "sqlite.h" #include "dbbe.h" @@ -40,11 +40,23 @@ # define sqliteMalloc(X) sqliteMalloc_(X,__FILE__,__LINE__) # define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__) # define sqliteRealloc(X,Y) sqliteRealloc_(X,Y,__FILE__,__LINE__) +# define sqliteStrDup(X) sqliteStrDup_(X,__FILE__,__LINE__) +# define sqliteStrNDup(X,Y) sqliteStrNDup_(X,Y,__FILE__,__LINE__) void sqliteStrRealloc(char**); #else # define sqliteStrRealloc(X) #endif +/* +** The following global variables are used for testing and debugging +** only. Thy only work if MEMORY_DEBUG is defined. +*/ +#ifdef MEMORY_DEBUG +int sqlite_nMalloc; /* Number of sqliteMalloc() calls */ +int sqlite_nFree; /* Number of sqliteFree() calls */ +int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ +#endif + /* ** The number of entries in the in-memory hash table holding the ** schema. @@ -306,10 +318,14 @@ int sqliteSortCompare(const char *, const char *); void *sqliteMalloc_(int,char*,int); void sqliteFree_(void*,char*,int); void *sqliteRealloc_(void*,int,char*,int); + char *sqliteStrDup_(const char*,char*,int); + char *sqliteStrNDup_(const char*, int,char*,int); #else void *sqliteMalloc(int); void sqliteFree(void*); void *sqliteRealloc(void*,int); + char *sqliteStrDup(const char*); + char *sqliteStrNDup(const char*, int); #endif int sqliteGetToken(const char*, int *); void sqliteSetString(char **, const char *, ...); diff --git a/src/tokenize.c b/src/tokenize.c index ef2726a4f5..b0f197efae 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -27,7 +27,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.9 2000/06/07 02:04:23 drh Exp $ +** $Id: tokenize.c,v 1.10 2000/06/08 13:36:40 drh Exp $ */ #include "sqliteInt.h" #include @@ -328,6 +328,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){ ** special SQL comments. Check for the special comments ** here and take approriate action if found. */ +#ifndef NDEBUG char *z = pParse->sLastToken.z; if( sqliteStrNICmp(z,"--parser-trace-on--",19)==0 ){ trace = stderr; @@ -339,7 +340,26 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){ pParse->db->flags |= SQLITE_VdbeTrace; }else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 18)==0 ){ pParse->db->flags &= ~SQLITE_VdbeTrace; +#ifdef MEMORY_DEBUG + }else if( sqliteStrNICmp(z,"--malloc-file=",14)==0 ){ + sqlite_iMallocFail = atoi(&z[14]); + }else if( sqliteStrNICmp(z,"--malloc-stats--", 16)==0 ){ + if( pParse->xCallback ){ + static char *azName[4] = {"malloc", "free", "to_fail", 0 }; + char *azArg[4]; + char zVal[3][30]; + sprintf(zVal[0],"%d", sqlite_nMalloc); + sprintf(zVal[1],"%d", sqlite_nFree); + sprintf(zVal[2],"%d", sqlite_iMallocFail); + azArg[0] = zVal[0]; + azArg[1] = zVal[1]; + azArg[2] = zVal[2]; + azArg[3] = 0; + pParse->xCallback(pParse->pArg, 3, azArg, azName); + } +#endif } +#endif break; } case TK_ILLEGAL: @@ -349,31 +369,36 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){ break; default: sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse); - if( pParse->zErrMsg ){ + if( pParse->zErrMsg && pParse->sErrToken.z ){ sqliteSetNString(pzErrMsg, "near \"", -1, pParse->sErrToken.z, pParse->sErrToken.n, "\": ", -1, pParse->zErrMsg, -1, 0); nErr++; + sqliteFree(pParse->zErrMsg); + pParse->zErrMsg = 0; } break; } } if( nErr==0 ){ sqliteParser(pEngine, 0, pParse->sLastToken, pParse); - if( pParse->zErrMsg ){ + if( pParse->zErrMsg && pParse->sErrToken.z ){ sqliteSetNString(pzErrMsg, "near \"", -1, pParse->sErrToken.z, pParse->sErrToken.n, "\": ", -1, pParse->zErrMsg, -1, 0); nErr++; + sqliteFree(pParse->zErrMsg); + pParse->zErrMsg = 0; } } sqliteParserFree(pEngine, free); if( pParse->zErrMsg ){ if( pzErrMsg ){ + sqliteFree(*pzErrMsg); *pzErrMsg = pParse->zErrMsg; }else{ sqliteFree(pParse->zErrMsg); diff --git a/src/util.c b/src/util.c index b3e0d7760c..5d53beb98d 100644 --- a/src/util.c +++ b/src/util.c @@ -26,7 +26,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.11 2000/06/05 16:01:39 drh Exp $ +** $Id: util.c,v 1.12 2000/06/08 13:36:41 drh Exp $ */ #include "sqliteInt.h" #include @@ -43,6 +43,11 @@ void *sqliteMalloc_(int n, char *zFile, int line){ void *p; int *pi; int k; + sqlite_nMalloc++; + if( sqlite_iMallocFail>=0 ){ + sqlite_iMallocFail--; + if( sqlite_iMallocFail==0 ) return 0; + } k = (n+sizeof(int)-1)/sizeof(int); pi = malloc( (3+k)*sizeof(int)); if( pi==0 ) return 0; @@ -65,6 +70,7 @@ void sqliteFree_(void *p, char *zFile, int line){ int *pi, k, n; pi = p; pi -= 2; + sqlite_nFree++; if( pi[0]!=0xdead1122 ){ fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p); return; @@ -123,7 +129,7 @@ void *sqliteRealloc_(void *oldP, int n, char *zFile, int line){ memset(oldPi, 0, (oldK+3)*sizeof(int)); free(oldPi); #if MEMORY_DEBUG>1 - fprintf(stderr,"realloc %d->%d bytes at 0x%x->0x%x at %s:%d\n", oldN, n, + fprintf(stderr,"realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n", oldN, n, (int)oldP, (int)p, zFile, line); #endif return p; @@ -142,6 +148,24 @@ void sqliteStrRealloc(char **pz){ *pz = zNew; } +/* +** Make a copy of a string in memory obtained from sqliteMalloc() +*/ +char *sqliteStrDup_(const char *z, char *zFile, int line){ + char *zNew = sqliteMalloc_(strlen(z)+1, zFile, line); + if( zNew ) strcpy(zNew, z); + return zNew; +} +char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){ + char *zNew = sqliteMalloc_(n+1, zFile, line); + if( zNew ){ + memcpy(zNew, z, n); + zNew[n] = 0; + } + return zNew; +} + + #else /* !defined(MEMORY_DEBUG) */ /* ** Allocate new memory and set it to zero. Return NULL if @@ -178,6 +202,23 @@ void *sqliteRealloc(void *p, int n){ } return realloc(p, n); } + +/* +** Make a copy of a string in memory obtained from sqliteMalloc() +*/ +char *sqliteStrDup(const char *z){ + char *zNew = sqliteMalloc(strlen(z)+1); + if( zNew ) strcpy(zNew, z); + return zNew; +} +char *sqliteStrNDup(const char *z, int n){ + char *zNew = sqliteMalloc(n+1); + if( zNew ){ + memcpy(zNew, z, n); + zNew[n] = 0; + } + return zNew; +} #endif /* MEMORY_DEBUG */ /* @@ -210,6 +251,11 @@ void sqliteSetString(char **pz, const char *zFirst, ...){ zResult += strlen(zResult); } va_end(ap); +#ifdef MEMORY_DEBUG +#if MEMORY_DEBUG>1 + fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz); +#endif +#endif } /* @@ -243,6 +289,11 @@ void sqliteSetNString(char **pz, ...){ zResult += n; } *zResult = 0; +#ifdef MEMORY_DEBUG +#if MEMORY_DEBUG>1 + fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz); +#endif +#endif va_end(ap); } diff --git a/src/vdbe.c b/src/vdbe.c index 1f99a61754..6fbb5bae98 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,7 +41,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.27 2000/06/07 15:39:04 drh Exp $ +** $Id: vdbe.c,v 1.28 2000/06/08 13:36:41 drh Exp $ */ #include "sqliteInt.h" #include @@ -254,7 +254,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2, const char *p3, int lbl){ } p->aOp[i].p2 = p2; if( p3 && p3[0] ){ - sqliteSetString(&p->aOp[i].p3, p3, 0); + p->aOp[i].p3 = sqliteStrDup(p3); }else{ p->aOp[i].p3 = 0; } @@ -523,8 +523,7 @@ static int hardStringify(Vdbe *p, int i){ p->aStack[i].flags |= STK_Str; return 0; } - p->zStack[i] = 0; - sqliteSetString(&p->zStack[i], zBuf, 0); + p->zStack[i] = sqliteStrDup(zBuf); if( p->zStack[i]==0 ) return 1; p->aStack[i].n = strlen(p->zStack[i])+1; p->aStack[i].flags |= STK_Str|STK_Dyn; @@ -846,7 +845,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){ return sHead.pNext; } - /* ** Execute the program in the VDBE. ** @@ -886,11 +884,17 @@ int sqliteVdbeExec( /* if( pzErrMsg ){ *pzErrMsg = 0; } */ for(pc=0; rc==SQLITE_OK && pcnOp && pc>=0; pc++){ pOp = &p->aOp[pc]; + + /* Only allow tracing if NDEBUG is not defined. + */ +#ifndef NDEBUG if( p->trace ){ fprintf(p->trace,"%4d %-12s %4d %4d %s\n", pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, pOp->p3 ? pOp->p3 : ""); } +#endif + switch( pOp->opcode ){ /* Opcode: Goto P2 * * ** @@ -1893,7 +1897,6 @@ int sqliteVdbeExec( */ case OP_KeyAsData: { int i = pOp->p1; - VdbeTable *pTab; if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ p->aTab[i].keyAsData = pOp->p2; } @@ -2683,6 +2686,7 @@ int sqliteVdbeExec( int i = pOp->p1; int tos = p->tos; Mem *pMem; + char *zOld; if( tos<0 ) goto not_enough_stack; if( i>=p->nMem ){ int nOld = p->nMem; @@ -2695,14 +2699,16 @@ int sqliteVdbeExec( } pMem = &p->aMem[i]; if( pMem->s.flags & STK_Dyn ){ - sqliteFree(pMem->z); + zOld = pMem->z; + }else{ + zOld = 0; } pMem->s = p->aStack[tos]; if( pMem->s.flags & STK_Str ){ - pMem->z = 0; - sqliteSetString(&pMem->z, p->zStack[tos], 0); + pMem->z = sqliteStrNDup(p->zStack[tos], pMem->s.n); pMem->s.flags |= STK_Dyn; } + if( zOld ) sqliteFree(zOld); PopStack(p, 1); break; } @@ -2824,6 +2830,12 @@ int sqliteVdbeExec( if( pFocus==0 ) goto no_mem; if( i>=0 && iagg.nMem ){ Mem *pMem = &pFocus->aMem[i]; + char *zOld; + if( pMem->s.flags & STK_Dyn ){ + zOld = pMem->z; + }else{ + zOld = 0; + } pMem->s = p->aStack[tos]; if( pMem->s.flags & STK_Str ){ pMem->z = sqliteMalloc( p->aStack[tos].n ); @@ -2831,6 +2843,7 @@ int sqliteVdbeExec( memcpy(pMem->z, p->zStack[tos], pMem->s.n); pMem->s.flags |= STK_Str|STK_Dyn; } + if( zOld ) sqliteFree(zOld); } PopStack(p, 1); break; @@ -2973,6 +2986,13 @@ int sqliteVdbeExec( break; } } + + /* The following code adds nothing to the actual functionality + ** of the program. It is only here for testing and debugging. + ** On the other hand, it does burn CPU cycles every time through + ** the evaluator loop. So we can leave it out when NDEBUG is defined. + */ +#ifndef NDEBUG if( pc<-1 || pc>=p->nOp ){ sqliteSetString(pzErrMsg, "jump destination out of range", 0); rc = SQLITE_INTERNAL; @@ -2999,6 +3019,7 @@ int sqliteVdbeExec( } fprintf(p->trace,"\n"); } +#endif } cleanup: diff --git a/test/tester.tcl b/test/tester.tcl index eb18a46ce1..cf132bf6da 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -23,7 +23,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.4 2000/05/31 17:59:27 drh Exp $ +# $Id: tester.tcl,v 1.5 2000/06/08 13:36:41 drh Exp $ # Create a test database # @@ -74,6 +74,7 @@ proc do_test {name cmd expected} { # proc finish_test {} { global nTest nErr + catch {db close} puts "$nErr errors out of $nTest tests" exit $nErr } diff --git a/tool/memleak.awk b/tool/memleak.awk new file mode 100644 index 0000000000..ca3366cf0d --- /dev/null +++ b/tool/memleak.awk @@ -0,0 +1,25 @@ +# +# This script looks for memory leaks by analyzing the output of "sqlite" +# when compiled with the MEMORY_DEBUG=2 option. +# +/^malloc / { + mem[$5] = $0 +} +/^realloc / { + mem[$7] = ""; + mem[$9] = $0 +} +/^free / { + mem[$5] = ""; +} +/^string at / { + addr = $3 + sub("string at " addr " is ","") + str[addr] = $0 +} +END { + for(addr in mem){ + if( mem[addr]=="" ) continue + print mem[addr], str[addr] + } +}