summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2015-08-03 07:17:27 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2015-08-03 07:17:27 (GMT)
commita46065fc3397a5a80b92980442a10e58bbadd912 (patch)
tree9d7bc92065a14ccc034c856e6fddd2721e59fd8d
parentec20498ab74fd4c48e24dcc7ecc9ff9e36b3ba72 (diff)
downloadtcl-a46065fc3397a5a80b92980442a10e58bbadd912.zip
tcl-a46065fc3397a5a80b92980442a10e58bbadd912.tar.gz
tcl-a46065fc3397a5a80b92980442a10e58bbadd912.tar.bz2
Backport the fixes to handling of continue in for-step clauses.
-rw-r--r--generic/tclExecute.c38
-rw-r--r--tests/for.test166
2 files changed, 189 insertions, 15 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index b9415e5..553abed 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -615,7 +615,7 @@ static void DeleteExecStack(ExecStack *esPtr);
static void DupExprCodeInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
static void FreeExprCodeInternalRep(Tcl_Obj *objPtr);
-static ExceptionRange * GetExceptRangeForPc(unsigned char *pc, int catchOnly,
+static ExceptionRange * GetExceptRangeForPc(unsigned char *pc, int searchMode,
ByteCode *codePtr);
static const char * GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
int *lengthPtr);
@@ -7347,7 +7347,7 @@ TclExecuteByteCode(
}
#endif
if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
- rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
+ rangePtr = GetExceptRangeForPc(pc, result, codePtr);
if (rangePtr == NULL) {
TRACE_APPEND(("no encl. loop or catch, returning %s\n",
StringForResultCode(result)));
@@ -7453,7 +7453,7 @@ TclExecuteByteCode(
#endif
goto abnormalReturn;
}
- rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
+ rangePtr = GetExceptRangeForPc(pc, TCL_ERROR, codePtr);
if (rangePtr == NULL) {
/*
* This is only possible when compiling a [catch] that sends its
@@ -7944,13 +7944,14 @@ GetSrcInfoForPc(
* ExceptionRange.
*
* Results:
- * In the normal case, catchOnly is 0 (false) and this procedure returns
- * a pointer to the most closely enclosing ExceptionRange structure
- * regardless of whether it is a loop or catch exception range. This is
- * appropriate when processing a TCL_BREAK or TCL_CONTINUE, which will be
- * "handled" either by a loop exception range or a closer catch range. If
- * catchOnly is nonzero, this procedure ignores loop exception ranges and
- * returns a pointer to the closest catch range. If no matching
+ * If the searchMode is TCL_ERROR, this procedure ignores loop exception
+ * ranges and returns a pointer to the closest catch range. If the
+ * searchMode is TCL_BREAK, this procedure returns a pointer to the most
+ * closely enclosing ExceptionRange regardless of whether it is a loop or
+ * catch exception range. If the searchMode is TCL_CONTINUE, this
+ * procedure returns a pointer to the most closely enclosing
+ * ExceptionRange (of any type) skipping only loop exception ranges if
+ * they don't have a sensible continueOffset defined. If no matching
* ExceptionRange is found that encloses pc, a NULL is returned.
*
* Side effects:
@@ -7965,10 +7966,12 @@ GetExceptRangeForPc(
* search for a closest enclosing exception
* range. This points to a bytecode
* instruction in codePtr's code. */
- int catchOnly, /* If 0, consider either loop or catch
- * ExceptionRanges in search. If nonzero
+ int searchMode, /* If TCL_BREAK, consider either loop or catch
+ * ExceptionRanges in search. If TCL_ERROR
* consider only catch ranges (and ignore any
- * closer loop ranges). */
+ * closer loop ranges). If TCL_CONTINUE, look
+ * for loop ranges that define a continue
+ * point or a catch range. */
ByteCode *codePtr) /* Points to the ByteCode in which to search
* for the enclosing ExceptionRange. */
{
@@ -7994,8 +7997,13 @@ GetExceptRangeForPc(
start = rangePtr->codeOffset;
if ((start <= pcOffset) &&
(pcOffset < (start + rangePtr->numCodeBytes))) {
- if ((!catchOnly)
- || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
+ if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
+ return rangePtr;
+ }
+ if (searchMode == TCL_BREAK) {
+ return rangePtr;
+ }
+ if (searchMode == TCL_CONTINUE && rangePtr->continueOffset != -1){
return rangePtr;
}
}
diff --git a/tests/for.test b/tests/for.test
index 8f19e9f..a0eeff6 100644
--- a/tests/for.test
+++ b/tests/for.test
@@ -811,6 +811,172 @@ test for-6.18 {Tcl_ForObjCmd: for command result} {
1 {invoked "continue" outside of a loop} \
]
+test for-8.0 {Coverity CID 1251203: break vs continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i; list a [eval {}]} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {6 5 3}
+test for-8.1 {Coverity CID 1251203: break vs continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i;list a [eval break]} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.2 {Coverity CID 1251203: break vs continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i;list a [eval continue]} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+test for-8.3 {break in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i; break} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.4 {continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i; continue} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+test for-8.5 {break in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i; list a [break]} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.6 {continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i; list a [continue]} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+test for-8.7 {break in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i;eval break} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.8 {continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ list a [\
+ for {set i 0} {$i < 5} {incr i;eval continue} {
+ incr j
+ }]
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+test for-8.9 {break in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ for {set i 0} {$i < 5} {incr i;eval break} {
+ incr j
+ }
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.10 {continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ for {set i 0} {$i < 5} {incr i;eval continue} {
+ incr j
+ }
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+test for-8.11 {break in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ for {set i 0} {$i < 5} {incr i;break} {
+ incr j
+ }
+ incr i
+ }
+ list $i $j $k
+ }}
+} {2 1 3}
+test for-8.12 {continue in for-step clause} {
+ apply {{} {
+ for {set k 0} {$k < 3} {incr k} {
+ set j 0
+ for {set i 0} {$i < 5} {incr i;continue} {
+ incr j
+ }
+ incr i
+ }
+ list $i $j $k
+ }}
+} {1 1 3}
+
# cleanup
::tcltest::cleanupTests