diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | generic/tclCompExpr.c | 34 | ||||
-rw-r--r-- | tests/compExpr.test | 25 |
3 files changed, 60 insertions, 6 deletions
@@ -1,3 +1,10 @@ +2007-08-24 Don Porter <dgp@users.sourceforge.net> + + * generic/tclCompExpr.c: Register literals found in expressions + * tests/compExpr.test: to restore literal sharing. Preserve numeric + intreps when literals are created for the first time. Correct memleak + in ExecConstantExprTree() and add test for the leak. + 2007-08-24 Miguel Sofer <msofer@users.sf.net> * generic/tclCompile.c: replaced copy loop that tripped some diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index 74e5528..942f82a 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompExpr.c,v 1.79 2007/08/23 17:20:07 dgp Exp $ + * RCS: @(#) $Id: tclCompExpr.c,v 1.80 2007/08/24 21:34:19 dgp Exp $ */ #include "tclInt.h" @@ -761,12 +761,27 @@ ParseExpr( switch (lexeme) { case NUMBER: - case BOOLEAN: + case BOOLEAN: { + if (interp) { + int new; + LiteralEntry *lePtr; + Tcl_Obj *objPtr = TclCreateLiteral((Interp *)interp, + (char *)start, scanned, + /* hash */ (unsigned int) -1, &new, + /* nsPtr */ NULL, /* flags */ 0, &lePtr); + if (new) { + lePtr->objPtr = literal; + Tcl_IncrRefCount(literal); + Tcl_DecrRefCount(objPtr); + } + } + Tcl_ListObjAppendElement(NULL, litList, literal); complete = lastParsed = OT_LITERAL; start += scanned; numBytes -= scanned; continue; + } default: break; } @@ -2067,6 +2082,9 @@ ExecConstantExprTree( TclEmitOpcode(INST_DONE, envPtr); Tcl_IncrRefCount(byteCodeObj); TclInitByteCodeObj(byteCodeObj, envPtr); + if (envPtr->localLitTable.buckets != envPtr->localLitTable.staticBuckets) { + ckfree((char *) envPtr->localLitTable.buckets); + } TclFreeCompileEnv(envPtr); TclStackFree(interp, envPtr); byteCodePtr = (ByteCode *) byteCodeObj->internalRep.otherValuePtr; @@ -2293,10 +2311,16 @@ CompileExprTree( case OT_EMPTY: numWords = 1; /* No arguments, so just the command */ break; - case OT_LITERAL: - TclEmitPush(TclAddLiteralObj(envPtr, *(*litObjvPtr)++, NULL), - envPtr); + case OT_LITERAL: { + Tcl_Obj *const *litObjv = *litObjvPtr; + Tcl_Obj *literal = *litObjv; + int length; + const char *bytes = Tcl_GetStringFromObj(literal, &length); + + TclEmitPush(TclRegisterNewLiteral(envPtr, bytes, length), envPtr); + (*litObjvPtr)++; break; + } case OT_TOKENS: TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); diff --git a/tests/compExpr.test b/tests/compExpr.test index 991033f..f2075df 100644 --- a/tests/compExpr.test +++ b/tests/compExpr.test @@ -8,7 +8,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: compExpr.test,v 1.13 2006/08/22 04:03:23 dgp Exp $ +# RCS: @(#) $Id: compExpr.test,v 1.14 2007/08/24 21:34:20 dgp Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -21,6 +21,9 @@ if {[catch {expr T1()} msg] && $msg eq {invalid command name "tcl::mathfunc::T1" testConstraint testmathfunctions 1 } +# Constrain memory leak tests +testConstraint memory [llength [info commands memory]] + catch {unset a} test compExpr-1.1 {TclCompileExpr procedure, successful expr parse and compile} { @@ -319,6 +322,26 @@ test compExpr-6.1 {LogSyntaxError procedure, error in expr longer than 60 chars} expr {(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)/} -1 foo 3 } -returnCodes error -match glob -result * +test compExpr-7.1 {Memory Leak} -constraints memory -setup { + proc getbytes {} { + set lines [split [memory info] \n] + lindex $lines 3 3 + } +} -body { + set end [getbytes] + for {set i 0} {$i < 5} {incr i} { + interp create slave + slave eval expr 1+2+3+4+5+6+7+8+9+10+11+12+13 + interp delete slave + set tmp $end + set end [getbytes] + } + set leakedBytes [expr {$end - $tmp}] +} -cleanup { + unset end i tmp + rename getbytes {} +} -result 0 + # cleanup catch {unset a} catch {unset b} |