summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin B Kenny <kennykb@acm.org>2010-11-03 00:18:57 (GMT)
committerKevin B Kenny <kennykb@acm.org>2010-11-03 00:18:57 (GMT)
commit86b28e0c4b2444435a30d345b3fe26daaf9de126 (patch)
tree13d5ab999b3265a8cce28582c5293a50ca1f3ef1
parent4086512001cd19c3cbf7d3c969fb83676e3f118f (diff)
downloadtcl-86b28e0c4b2444435a30d345b3fe26daaf9de126.zip
tcl-86b28e0c4b2444435a30d345b3fe26daaf9de126.tar.gz
tcl-86b28e0c4b2444435a30d345b3fe26daaf9de126.tar.bz2
merge
-rw-r--r--ChangeLog13
-rw-r--r--generic/tclCompCmds.c171
-rw-r--r--library/safe.tcl8
-rw-r--r--library/tzdata/Asia/Hong_Kong2
-rw-r--r--library/tzdata/Pacific/Apia2
-rw-r--r--library/tzdata/Pacific/Fiji2
-rw-r--r--tests/compile.test32
-rw-r--r--tests/safe.test4
8 files changed, 155 insertions, 79 deletions
diff --git a/ChangeLog b/ChangeLog
index cc9105c..42100ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,15 @@
-2010-10-28 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
+2010-11-01 Stuart Cassoff <stwo@users.sourceforge.net>
+
+ * library/safe.tcl: Improved handling of non-standard module
+ * tests/safe.test: path lists, empty path lists in particular.
+
+2010-11-01 Kevin B. Kenny <kennykb@acm.org>
+
+ * library/tzdata/Asia/Hong_Kong:
+ * library/tzdata/Pacific/Apia:
+ * library/tzdata/Pacific/Fiji: Olson's tzdata2010o.
+
+2010-10-29 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
* generic/tclTimer.c: Stop small [afters] from wasting CPU [Bug
2905784] while keeping accuracy.
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index 4dde235..044d9b1 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclCompCmds.c,v 1.169.2.1 2010/10/23 15:49:54 kennykb Exp $
+ * RCS: @(#) $Id: tclCompCmds.c,v 1.169.2.2 2010/11/03 00:18:57 kennykb Exp $
*/
#include "tclInt.h"
@@ -279,7 +279,8 @@ TclCompileCatchCmd(
Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
const char *name;
int resultIndex, optsIndex, nameChars, range;
- int savedStackDepth = envPtr->currStackDepth;
+ int initStackDepth = envPtr->currStackDepth;
+ int savedStackDepth;
DefineLineInformation; /* TIP #280 */
/*
@@ -345,112 +346,148 @@ TclCompileCatchCmd(
}
/*
- * We will compile the catch command. Emit a beginCatch instruction at the
- * start of the catch body: the subcommand it controls.
+ * We will compile the catch command. Declare the exception range
+ * that it uses.
*/
range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
- TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);
/*
- * If the body is a simple word, compile the instructions to eval it.
- * Otherwise, compile instructions to substitute its text without
- * catching, a catch instruction that resets the stack to what it was
- * before substituting the body, and then an instruction to eval the body.
- * Care has to be taken to register the correct startOffset for the catch
- * range so that errors in the substitution are not caught. [Bug 219184]
+ * If the body is a simple word, compile a BEGIN_CATCH instruction,
+ * followed by the instructions to eval the body.
+ * Otherwise, compile instructions to substitute the body text before
+ * starting the catch, then BEGIN_CATCH, and then EVAL_STK to
+ * evaluate the substituted body.
+ * Care has to be taken to make sure that substitution happens outside
+ * the catch range so that errors in the substitution are not caught.
+ * [Bug 219184]
+ * The reason for duplicating the script is that EVAL_STK would otherwise
+ * begin by undeflowing the stack below the mark set by BEGIN_CATCH4.
*/
SetLineInformation(1);
if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
+ savedStackDepth = envPtr->currStackDepth;
+ TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
CompileBody(envPtr, cmdTokenPtr, interp);
- ExceptionRangeEnds(envPtr, range);
} else {
CompileTokens(envPtr, cmdTokenPtr, interp);
+ savedStackDepth = envPtr->currStackDepth;
+ TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
+ TclEmitOpcode(INST_DUP, envPtr);
TclEmitOpcode(INST_EVAL_STK, envPtr);
- ExceptionRangeEnds(envPtr, range);
+ }
+ /* Stack at this point:
+ * nonsimple: script <mark> result
+ * simple: <mark> result
+ */
+
+ /*
+ * Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch
+ * result, and jump around the "error case" code.
+ */
+
+ PushLiteral(envPtr, "0", 1);
+ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
+ /* Stack at this point: ?script? <mark> result TCL_OK */
+
+ /*
+ * Emit the "error case" epilogue. Push the interpreter result
+ * and the return code.
+ */
+
+ envPtr->currStackDepth = savedStackDepth;
+ ExceptionRangeTarget(envPtr, range, catchOffset);
+ /* Stack at this point: ?script? */
+ TclEmitOpcode(INST_PUSH_RESULT, envPtr);
+ TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
+
+ /*
+ * Update the target of the jump after the "no errors" code.
+ */
+
+ /* Stack at this point: ?script? result returnCode */
+ if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
+ Tcl_Panic("TclCompileCatchCmd: bad jump distance %d",
+ CurrentOffset(envPtr) - jumpFixup.codeOffset);
+ }
+
+ /* Push the return options if the caller wants them */
+
+ if (optsIndex != -1) {
+ TclEmitOpcode(INST_PUSH_RETURN_OPTIONS, envPtr);
+ }
+
+ /*
+ * End the catch
+ */
+
+ ExceptionRangeEnds(envPtr, range);
+ TclEmitOpcode(INST_END_CATCH, envPtr);
+
+ /*
+ * At this point, the top of the stack is inconveniently ordered:
+ * ?script? result returnCode ?returnOptions?
+ * Reverse the stack to bring the result to the top.
+ */
+
+ if (optsIndex != -1) {
+ TclEmitInstInt4(INST_REVERSE, 3, envPtr);
+ } else {
+ TclEmitInstInt4(INST_REVERSE, 2, envPtr);
}
/*
- * The "no errors" epilogue code: store the body's result into the
- * variable (if any), push "0" (TCL_OK) as the catch's "no error" result,
- * and jump around the "error case" code. Note that we issue the push of
- * the return options first so that if alterations happen to the current
- * interpreter state during the writing of the variable, we won't see
- * them; this results in a slightly complex instruction issuing flow
- * (can't exchange, only duplicate and pop).
+ * Store the result if requested, and remove it from the stack
*/
if (resultIndex != -1) {
- if (optsIndex != -1) {
- TclEmitOpcode(INST_PUSH_RETURN_OPTIONS, envPtr);
- TclEmitInstInt4(INST_OVER, 1, envPtr);
- }
if (resultIndex <= 255) {
TclEmitInstInt1(INST_STORE_SCALAR1, resultIndex, envPtr);
} else {
TclEmitInstInt4(INST_STORE_SCALAR4, resultIndex, envPtr);
}
- if (optsIndex != -1) {
- TclEmitOpcode(INST_POP, envPtr);
- if (optsIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, optsIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_STORE_SCALAR4, optsIndex, envPtr);
- }
- TclEmitOpcode(INST_POP, envPtr);
- }
}
TclEmitOpcode(INST_POP, envPtr);
- PushLiteral(envPtr, "0", 1);
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
/*
- * The "error case" code: store the body's result into the variable (if
- * any), then push the error result code. The initial PC offset here is
- * the catch's error target. Note that if we are saving the return
- * options, we do that first so the preservation cannot get affected by
- * any intermediate result handling.
+ * Stack is now ?script? result returnCode.
+ * If the options dict has been requested, it is buried on the stack
+ * under the return code. Reverse the stack to bring it to the top,
+ * store it and remove it from the stack.
*/
- envPtr->currStackDepth = savedStackDepth;
- ExceptionRangeTarget(envPtr, range, catchOffset);
- if (resultIndex != -1) {
- if (optsIndex != -1) {
- TclEmitOpcode(INST_PUSH_RETURN_OPTIONS, envPtr);
- }
- TclEmitOpcode(INST_PUSH_RESULT, envPtr);
- if (resultIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, resultIndex, envPtr);
+ if (optsIndex != -1) {
+ TclEmitInstInt4(INST_REVERSE, 2, envPtr);
+ if (optsIndex <= 255) {
+ TclEmitInstInt1(INST_STORE_SCALAR1, optsIndex, envPtr);
} else {
- TclEmitInstInt4(INST_STORE_SCALAR4, resultIndex, envPtr);
+ TclEmitInstInt4(INST_STORE_SCALAR4, optsIndex, envPtr);
}
TclEmitOpcode(INST_POP, envPtr);
- if (optsIndex != -1) {
- if (optsIndex <= 255) {
- TclEmitInstInt1(INST_STORE_SCALAR1, optsIndex, envPtr);
- } else {
- TclEmitInstInt4(INST_STORE_SCALAR4, optsIndex, envPtr);
- }
- TclEmitOpcode(INST_POP, envPtr);
- }
}
- TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
- /*
- * Update the target of the jump after the "no errors" code, then emit an
- * endCatch instruction at the end of the catch command.
+ /*
+ * Stack is now ?script? result. Get rid of the subst'ed script
+ * if it's hanging arond.
*/
- if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
- Tcl_Panic("TclCompileCatchCmd: bad jump distance %d",
- CurrentOffset(envPtr) - jumpFixup.codeOffset);
+ if (cmdTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
+ TclEmitInstInt4(INST_REVERSE, 2, envPtr);
+ TclEmitOpcode(INST_POP, envPtr);
}
- TclEmitOpcode(INST_END_CATCH, envPtr);
- envPtr->currStackDepth = savedStackDepth + 1;
+ /*
+ * Result of all this, on either branch, should have been to leave
+ * one operand -- the return code -- on the stack.
+ */
+
+ if (envPtr->currStackDepth != initStackDepth + 1) {
+ Tcl_Panic("in TclCompileCatchCmd, currStackDepth = %d should be %d",
+ envPtr->currStackDepth, initStackDepth+1);
+ }
return TCL_OK;
}
diff --git a/library/safe.tcl b/library/safe.tcl
index 0cae5fd..c35193b 100644
--- a/library/safe.tcl
+++ b/library/safe.tcl
@@ -12,7 +12,7 @@
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: safe.tcl,v 1.41 2010/09/02 18:31:00 andreas_kupries Exp $
+# RCS: @(#) $Id: safe.tcl,v 1.41.2.1 2010/11/03 00:18:57 kennykb Exp $
#
# The implementation is based on namespaces. These naming conventions are
@@ -500,9 +500,9 @@ proc ::safe::InterpInit {
# Sync the paths used to search for Tcl modules. This can be done only
# now, after tm.tcl was loaded.
namespace upvar ::safe S$slave state
- ::interp eval $slave [list \
- ::tcl::tm::add {*}$state(tm_path_slave)]
-
+ if {[llength $state(tm_path_slave)] > 0} {
+ ::interp eval $slave [list ::tcl::tm::add {*}$state(tm_path_slave)]
+ }
return $slave
}
diff --git a/library/tzdata/Asia/Hong_Kong b/library/tzdata/Asia/Hong_Kong
index 8304a62..928cde6 100644
--- a/library/tzdata/Asia/Hong_Kong
+++ b/library/tzdata/Asia/Hong_Kong
@@ -70,8 +70,6 @@ set TZData(:Asia/Hong_Kong) {
{182889000 28800 0 HKT}
{198617400 32400 1 HKST}
{214338600 28800 0 HKT}
- {230067000 32400 1 HKST}
- {245788200 28800 0 HKT}
{295385400 32400 1 HKST}
{309292200 28800 0 HKT}
}
diff --git a/library/tzdata/Pacific/Apia b/library/tzdata/Pacific/Apia
index c97a156..2db52b6 100644
--- a/library/tzdata/Pacific/Apia
+++ b/library/tzdata/Pacific/Apia
@@ -6,5 +6,5 @@ set TZData(:Pacific/Apia) {
{-1861878784 -41400 0 SAMT}
{-631110600 -39600 0 WST}
{1285498800 -36000 1 WSDT}
- {1301824800 -39600 0 WST}
+ {1301828400 -39600 0 WST}
}
diff --git a/library/tzdata/Pacific/Fiji b/library/tzdata/Pacific/Fiji
index 67f84cb..3b7aabe 100644
--- a/library/tzdata/Pacific/Fiji
+++ b/library/tzdata/Pacific/Fiji
@@ -10,5 +10,5 @@ set TZData(:Pacific/Fiji) {
{1259416800 46800 1 FJST}
{1269698400 43200 0 FJT}
{1287842400 46800 1 FJST}
- {1301148000 43200 0 FJT}
+ {1299333600 43200 0 FJT}
}
diff --git a/tests/compile.test b/tests/compile.test
index d9567cc..021c6fe 100644
--- a/tests/compile.test
+++ b/tests/compile.test
@@ -11,7 +11,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: compile.test,v 1.51 2009/10/29 17:21:48 dgp Exp $
+# RCS: @(#) $Id: compile.test,v 1.51.4.1 2010/11/03 00:18:57 kennykb Exp $
package require tcltest 2
namespace import -force ::tcltest::*
@@ -128,6 +128,36 @@ test compile-3.5 {TclCompileCatchCmd: recover from error, [Bug 705406]} {
}
list [catch foo msg] $msg
} {0 1}
+test compile-3.6 {TclCompileCatchCmd: error in storing result [Bug 3098302]} {*}{
+ -setup {
+ namespace eval catchtest {
+ variable result1 {}
+ }
+ trace add variable catchtest::result1 write catchtest::failtrace
+ proc catchtest::failtrace {n1 n2 op} {
+ return -code error "trace on $n1 fails by request"
+ }
+ }
+ -body {
+ proc catchtest::x {} {
+ variable result1
+ set count 0
+ for {set i 0} {$i < 10} {incr i} {
+ set status2 [catch {
+ set status1 [catch {
+ return -code error -level 0 "original failure"
+ } result1 options1]
+ } result2 options2]
+ incr count
+ }
+ list $count $result2
+ }
+ catchtest::x
+ }
+ -result {10 {can't set "result1": trace on result1 fails by request}}
+ -cleanup {namespace delete catchtest}
+}
+
test compile-4.1 {TclCompileForCmd: command substituted test expression} {
set i 0
diff --git a/tests/safe.test b/tests/safe.test
index c22cf6e..ee2ecc3 100644
--- a/tests/safe.test
+++ b/tests/safe.test
@@ -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: safe.test,v 1.34 2010/08/18 13:31:55 dkf Exp $
+# RCS: @(#) $Id: safe.test,v 1.34.2.1 2010/11/03 00:18:57 kennykb Exp $
package require Tcl 8.5
@@ -205,7 +205,7 @@ test safe-7.2 {tests specific path and interpFind/AddToAccessPath} -body {
[catch {interp eval $i {package require http 1}} msg] $msg \
[safe::interpConfigure $i]\
[safe::interpDelete $i]
-} -match glob -result "{\$p(:0:)} {\$p(:[expr 1+[llength [tcl::tm::list]]]:)} 1 {can't find package http 1} {-accessPath {[list $tcl_library * /dummy/unixlike/test/path]} -statics 0 -nested 1 -deleteHook {}} {}"
+} -match glob -result "{\$p(:0:)} {\$p(:[expr 1+[llength [tcl::tm::list]]]:)} 1 {can't find package http 1} {-accessPath {[list $tcl_library */dummy/unixlike/test/path]} -statics 0 -nested 1 -deleteHook {}} {}"
# test source control on file name
test safe-8.1 {safe source control on file} -setup {