-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
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
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
-305b043f4f71278d6d2c32e6e457f63efefae20d
\ No newline at end of file
+bf98cf82a73c54c4eced04994bb1a019844dfc03
\ No newline at end of file
** 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"
pNext = pIndex->pNext;
sqliteDeleteIndex(db, pIndex);
}
+ sqliteFree(pTable->zName);
sqliteFree(pTable->aCol);
sqliteFree(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;
}
*************************************************************************
** 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"
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; i<pTabList->nId; i++){
int j;
Table *pTab = pTabList->a[i].pTab;
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; i<pTabList->nId; i++){
int j;
char *zTab;
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;
** 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}
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);}
** 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"
}
zSortOrder[pOrderBy->nExpr] = 0;
sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, 0);
+ sqliteFree(zSortOrder);
sqliteVdbeAddOp(v, OP_SortPut, 0, 0, 0, 0);
}else
for(j=0; j<pEList->nExpr; 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;
*************************************************************************
** 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"
# 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.
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 *, ...);
** 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 <ctype.h>
** 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;
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:
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);
** 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 <stdarg.h>
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;
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;
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;
*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
}
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 */
/*
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
}
/*
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);
}
** 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 <unistd.h>
}
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;
}
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;
return sHead.pNext;
}
-
/*
** Execute the program in the VDBE.
**
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(pc=0; rc==SQLITE_OK && pc<p->nOp && 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 * *
**
*/
case OP_KeyAsData: {
int i = pOp->p1;
- VdbeTable *pTab;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){
p->aTab[i].keyAsData = pOp->p2;
}
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;
}
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;
}
if( pFocus==0 ) goto no_mem;
if( i>=0 && i<p->agg.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 );
memcpy(pMem->z, p->zStack[tos], pMem->s.n);
pMem->s.flags |= STK_Str|STK_Dyn;
}
+ if( zOld ) sqliteFree(zOld);
}
PopStack(p, 1);
break;
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;
}
fprintf(p->trace,"\n");
}
+#endif
}
cleanup:
# 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
#
#
proc finish_test {} {
global nTest nErr
+ catch {db close}
puts "$nErr errors out of $nTest tests"
exit $nErr
}
--- /dev/null
+#
+# 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]
+ }
+}