summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--generic/tclCompExpr.c34
-rw-r--r--tests/compExpr.test25
3 files changed, 60 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index d8ed2ee..8f95f79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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}