Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix the memory leak introduced by check-in (725). (CVS 726) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b957dafc26383af514795df18bc7b8f3 |
User & Date: | drh 2002-08-25 18:29:12.000 |
Context
2002-08-25
| ||
19:20 | Fix for ticket #136: Added the OP_RenameCursor VDBE instruction and used it to make cursor numbers right on nested subqueries. Also added OP_Gosub and OP_Return but have not actually used them for anything yet. (CVS 727) (check-in: c602603e7c user: drh tags: trunk) | |
18:29 | Fix the memory leak introduced by check-in (725). (CVS 726) (check-in: b957dafc26 user: drh tags: trunk) | |
2002-08-24
| ||
18:24 | Change the way token memory is allocated in an effort to fix ticket #136. There is now a memory leak when using views of views. (CVS 725) (check-in: 22d8726e61 user: drh tags: trunk) | |
Changes
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.109 2002/08/25 18:29:12 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
804 805 806 807 808 809 810 811 812 813 814 815 816 817 | pParse->nErr++; return 1; } if( pTab->pSelect ){ if( sqliteViewGetColumnNames(pParse, pTab) ){ return 1; } pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); } } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ | > | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | pParse->nErr++; return 1; } if( pTab->pSelect ){ if( sqliteViewGetColumnNames(pParse, pTab) ){ return 1; } sqliteSelectDelete(pTabList->a[i].pSelect); pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); } } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ |
︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 | if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){ Expr *pNew; assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 ); pNew = pEList->a[pExpr->iColumn].pExpr; assert( pNew!=0 ); pExpr->op = pNew->op; pExpr->pLeft = sqliteExprDup(pNew->pLeft); pExpr->pRight = sqliteExprDup(pNew->pRight); pExpr->pList = sqliteExprListDup(pNew->pList); pExpr->iTable = pNew->iTable; pExpr->iColumn = pNew->iColumn; pExpr->iAgg = pNew->iAgg; pExpr->nFuncName = pNew->nFuncName; sqliteTokenCopy(&pExpr->token, &pNew->token); if( iSub!=iTable ){ | > > > | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 | if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){ Expr *pNew; assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 ); pNew = pEList->a[pExpr->iColumn].pExpr; assert( pNew!=0 ); pExpr->op = pNew->op; assert( pExpr->pLeft==0 ); pExpr->pLeft = sqliteExprDup(pNew->pLeft); assert( pExpr->pRight==0 ); pExpr->pRight = sqliteExprDup(pNew->pRight); assert( pExpr->pList==0 ); pExpr->pList = sqliteExprListDup(pNew->pList); pExpr->iTable = pNew->iTable; pExpr->iColumn = pNew->iColumn; pExpr->iAgg = pNew->iAgg; pExpr->nFuncName = pNew->nFuncName; sqliteTokenCopy(&pExpr->token, &pNew->token); if( iSub!=iTable ){ |
︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 | } p->nOffset += pSub->nOffset; if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ sqliteDeleteTable(0, pSrc->a[iFrom].pTab); } pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab; pSubSrc->a[0].pTab = 0; pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect; pSubSrc->a[0].pSelect = 0; sqliteSelectDelete(pSub); return 1; } /* | > | 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 | } p->nOffset += pSub->nOffset; if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ sqliteDeleteTable(0, pSrc->a[iFrom].pTab); } pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab; pSubSrc->a[0].pTab = 0; assert( pSrc->a[iFrom].pSelect==pSub ); pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect; pSubSrc->a[0].pSelect = 0; sqliteSelectDelete(pSub); return 1; } /* |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** ** $Id: util.c,v 1.49 2002/08/25 18:29:12 drh Exp $ */ #include "sqliteInt.h" #include <stdarg.h> #include <ctype.h> /* ** If malloc() ever fails, this global variable gets set to 1. |
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /* ** For keeping track of the number of mallocs and frees. This ** is used to check for memory leaks. */ int sqlite_nMalloc; /* Number of sqliteMalloc() calls */ int sqlite_nFree; /* Number of sqliteFree() calls */ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ /* ** Allocate new memory and set it to zero. Return NULL if ** no memory is available. */ void *sqliteMalloc_(int n, char *zFile, int line){ | > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* ** For keeping track of the number of mallocs and frees. This ** is used to check for memory leaks. */ int sqlite_nMalloc; /* Number of sqliteMalloc() calls */ int sqlite_nFree; /* Number of sqliteFree() calls */ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ #if MEMORY_DEBUG>1 static int memcnt = 0; #endif /* ** Allocate new memory and set it to zero. Return NULL if ** no memory is available. */ void *sqliteMalloc_(int n, char *zFile, int line){ |
︙ | ︙ | |||
71 72 73 74 75 76 77 | sqlite_nMalloc++; pi[0] = 0xdead1122; pi[1] = n; pi[k+2] = 0xdead3344; p = &pi[2]; memset(p, 0, n); #if MEMORY_DEBUG>1 | | > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | sqlite_nMalloc++; pi[0] = 0xdead1122; pi[1] = n; pi[k+2] = 0xdead3344; p = &pi[2]; memset(p, 0, n); #if MEMORY_DEBUG>1 fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n", ++memcnt, n, (int)p, zFile,line); #endif return p; } /* ** Free memory previously obtained from sqliteMalloc() */ |
︙ | ︙ | |||
97 98 99 100 101 102 103 | k = (n+sizeof(int)-1)/sizeof(int); if( pi[k+2]!=0xdead3344 ){ fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p); return; } memset(pi, 0xff, (k+3)*sizeof(int)); #if MEMORY_DEBUG>1 | > | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | k = (n+sizeof(int)-1)/sizeof(int); if( pi[k+2]!=0xdead3344 ){ fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p); return; } memset(pi, 0xff, (k+3)*sizeof(int)); #if MEMORY_DEBUG>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 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | memcpy(p, oldP, n>oldN ? oldN : n); if( n>oldN ){ memset(&((char*)p)[oldN], 0, n-oldN); } memset(oldPi, 0, (oldK+3)*sizeof(int)); free(oldPi); #if MEMORY_DEBUG>1 | | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | memcpy(p, oldP, n>oldN ? oldN : n); if( n>oldN ){ memset(&((char*)p)[oldN], 0, n-oldN); } memset(oldPi, 0, (oldK+3)*sizeof(int)); free(oldPi); #if MEMORY_DEBUG>1 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); #endif return p; } /* ** Make a duplicate of a string into memory obtained from malloc() ** Free the original string using sqliteFree(). |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.170 2002/08/25 18:29:13 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
248 249 250 251 252 253 254 255 256 257 258 259 260 261 | int nSet; /* Number of sets allocated */ Set *aSet; /* An array of sets */ int nCallback; /* Number of callbacks invoked so far */ int keylistStackDepth; /* The size of the "keylist" stack */ Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ }; /* ** Create a new virtual database engine. */ Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; | > > > > > > > > > > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | int nSet; /* Number of sets allocated */ Set *aSet; /* An array of sets */ int nCallback; /* Number of callbacks invoked so far */ int keylistStackDepth; /* The size of the "keylist" stack */ Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ }; /* ** When debugging the code generator in a symbolic debugger, on can ** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed ** as they are added to the instruction stream. */ #ifndef NDEBUG int sqlite_vdbe_addop_trace = 0; static void vdbePrintOp(FILE*, int, Op*); #endif /* ** Create a new virtual database engine. */ Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *p; p = sqliteMalloc( sizeof(Vdbe) ); if( p==0 ) return 0; |
︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 | p->aOp[i].p1 = p1; if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){ p2 = p->aLabel[-1-p2]; } p->aOp[i].p2 = p2; p->aOp[i].p3 = 0; p->aOp[i].p3type = P3_NOTUSED; return i; } /* ** Create a new symbolic label for an instruction that has yet to be ** coded. The symbolic label is really just a negative number. The ** label can be used as the P2 value of an operation. Later, when | > > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | p->aOp[i].p1 = p1; if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){ p2 = p->aLabel[-1-p2]; } p->aOp[i].p2 = p2; p->aOp[i].p3 = 0; p->aOp[i].p3type = P3_NOTUSED; #ifndef NDEBUG if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i, &p->aOp[i]); #endif return i; } /* ** Create a new symbolic label for an instruction that has yet to be ** coded. The symbolic label is really just a negative number. The ** label can be used as the P2 value of an operation. Later, when |
︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 403 404 405 406 | if( nOp>0 ){ int i; for(i=0; i<nOp; i++){ int p2 = aOp[i].p2; p->aOp[i+addr] = aOp[i]; if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2); p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED; } p->nOp += nOp; } return addr; } /* | > > > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | if( nOp>0 ){ int i; for(i=0; i<nOp; i++){ int p2 = aOp[i].p2; p->aOp[i+addr] = aOp[i]; if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2); p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED; #ifndef NDEBUG if( sqlite_vdbe_addop_trace ) vdbePrintOp(0, i+addr, &p->aOp[i+addr]); #endif } p->nOp += nOp; } return addr; } /* |
︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | break; } } zBuf[i] = 0; return i>0 ? zBuf : 0; } /* ** Execute the program in the VDBE. ** ** If an error occurs, an error message is written to memory obtained ** from sqliteMalloc() and *pzErrMsg is made to point to that memory. ** The return parameter is the number of errors. ** | > > > > > > > > > > > > > > > > > > > > | 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | break; } } zBuf[i] = 0; return i>0 ? zBuf : 0; } #ifndef NDEBUG /* ** Print a single opcode. This routine is used for debugging only. */ static void vdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP3; char zPtr[40]; if( pOp->p3type==P3_POINTER ){ sprintf(zPtr, "ptr(%#x)", (int)pOp->p3); zP3 = zPtr; }else{ zP3 = pOp->p3; } if( pOut==0 ) pOut = stdout; fprintf(pOut,"%4d %-12s %4d %4d %s\n", pc, zOpName[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : ""); fflush(pOut); } #endif /* ** Execute the program in the VDBE. ** ** If an error occurs, an error message is written to memory obtained ** from sqliteMalloc() and *pzErrMsg is made to point to that memory. ** The return parameter is the number of errors. ** |
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | break; } /* Only allow tracing if NDEBUG is not defined. */ #ifndef NDEBUG if( p->trace ){ | < < < < < < < < < < | | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 | break; } /* Only allow tracing if NDEBUG is not defined. */ #ifndef NDEBUG if( p->trace ){ vdbePrintOp(p->trace, pc, pOp); } #endif switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a |
︙ | ︙ |
Changes to test/view.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2002 February 26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing VIEW statements. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2002 February 26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing VIEW statements. # # $Id: view.test,v 1.10 2002/08/25 18:29:16 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test view-1.0 { execsql { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); |
︙ | ︙ | |||
267 268 269 270 271 272 273 | do_test view-8.1 { execsql { CREATE VIEW v6 AS SELECT pqr, xyz FROM v1; SELECT * FROM v6 ORDER BY xyz; } } {7 2 13 5 19 8 27 12} | < > | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | do_test view-8.1 { execsql { CREATE VIEW v6 AS SELECT pqr, xyz FROM v1; SELECT * FROM v6 ORDER BY xyz; } } {7 2 13 5 19 8 27 12} do_test view-8.2 { db close sqlite db test.db execsql { SELECT * FROM v6 ORDER BY xyz; } } {7 2 13 5 19 8 27 12} do_test view-8.3 { execsql { CREATE VIEW v7 AS SELECT pqr+xyz AS a FROM v6; SELECT * FROM v7 ORDER BY a; } } {9 18 27 39} if 0 { do_test view-8.4 { execsql { PRAGMA vdbe_trace=on; CREATE VIEW v8 AS SELECT max(cnt) FROM (SELECT a%2 AS eo, count(*) AS cnt FROM t1 GROUP BY eo); SELECT * FROM v8; } } 3 } finish_test |
Changes to tool/memleak.awk.
1 2 3 4 | # # This script looks for memory leaks by analyzing the output of "sqlite" # when compiled with the MEMORY_DEBUG=2 option. # | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # This script looks for memory leaks by analyzing the output of "sqlite" # when compiled with the MEMORY_DEBUG=2 option. # /[0-9]+ malloc / { mem[$6] = $0 } /[0-9]+ realloc / { mem[$8] = ""; mem[$10] = $0 } /[0-9]+ free / { mem[$6] = ""; str[$6] = "" } /^string at / { addr = $4 sub("string at " addr " is ","") str[addr] = $0 } END { for(addr in mem){ if( mem[addr]=="" ) continue print mem[addr], str[addr] |
︙ | ︙ |