Tcl Source Code

Check-in [0710a46828]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Backport the fixes to handling of continue in for-step clauses.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: 0710a46828a997a963466ea7e51fb51f88c2521d
User & Date: dkf 2015-08-03 07:17:27
Context
2015-09-24
19:05
Remove the backport that causes stack balance panics. check-in: aeb89a1f10 user: dgp tags: bug-05489ce335
2015-08-06
04:24
Fix [6f74ac47278f437a]: No man link to Tcl_UtfNcasecmp() during install on unix check-in: c4aba48855 user: jan.nijtmans tags: core-8-5-branch
2015-08-03
09:57
merge mark check-in: 2c8fc45c70 user: dkf tags: trunk
09:55
merge mark Closed-Leaf check-in: b28720a3d7 user: dkf tags: mistake
07:17
Backport the fixes to handling of continue in for-step clauses. check-in: 0710a46828 user: dkf tags: core-8-5-branch
2015-07-29
14:54
[3e7eca8c8c] Prevent overflow in size values passed to allocators. check-in: ee467fed92 user: dgp tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclExecute.c.

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
			    unsigned char *pc, int stackTop,
			    int stackLowerBound, int checkStack);
#endif /* TCL_COMPILE_DEBUG */
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,
			    ByteCode *codePtr);
static const char *	GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
			    int *lengthPtr);
static Tcl_Obj **	GrowEvaluationStack(ExecEnv *eePtr, int growth,
			    int move);
static void		IllegalExprOperandType(Tcl_Interp *interp,
			    unsigned char *pc, Tcl_Obj *opndPtr);







|







611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
			    unsigned char *pc, int stackTop,
			    int stackLowerBound, int checkStack);
#endif /* TCL_COMPILE_DEBUG */
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 searchMode,
			    ByteCode *codePtr);
static const char *	GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
			    int *lengthPtr);
static Tcl_Obj **	GrowEvaluationStack(ExecEnv *eePtr, int growth,
			    int move);
static void		IllegalExprOperandType(Tcl_Interp *interp,
			    unsigned char *pc, Tcl_Obj *opndPtr);
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
	    TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
	    break;
	default:
	    TRACE(("=> "));
	}
#endif
	if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
	    rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
	    if (rangePtr == NULL) {
		TRACE_APPEND(("no encl. loop or catch, returning %s\n",
			StringForResultCode(result)));
		goto abnormalReturn;
	    }
	    if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
		TRACE_APPEND(("%s ...\n", StringForResultCode(result)));







|







7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
	    TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
	    break;
	default:
	    TRACE(("=> "));
	}
#endif
	if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
	    rangePtr = GetExceptRangeForPc(pc, result, codePtr);
	    if (rangePtr == NULL) {
		TRACE_APPEND(("no encl. loop or catch, returning %s\n",
			StringForResultCode(result)));
		goto abnormalReturn;
	    }
	    if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
		TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
	    if (traceInstructions) {
		fprintf(stdout, "   ... no enclosing catch, returning %s\n",
			StringForResultCode(result));
	    }
#endif
	    goto abnormalReturn;
	}
	rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
	if (rangePtr == NULL) {
	    /*
	     * This is only possible when compiling a [catch] that sends its
	     * script to INST_EVAL. Cannot correct the compiler without
	     * breakingcompat with previous .tbc compiled scripts.
	     */








|







7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
	    if (traceInstructions) {
		fprintf(stdout, "   ... no enclosing catch, returning %s\n",
			StringForResultCode(result));
	    }
#endif
	    goto abnormalReturn;
	}
	rangePtr = GetExceptRangeForPc(pc, TCL_ERROR, codePtr);
	if (rangePtr == NULL) {
	    /*
	     * This is only possible when compiling a [catch] that sends its
	     * script to INST_EVAL. Cannot correct the compiler without
	     * breakingcompat with previous .tbc compiled scripts.
	     */

7940
7941
7942
7943
7944
7945
7946


7947
7948
7949
7950
7951

7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971


7972
7973
7974
7975
7976
7977
7978
 *
 * GetExceptRangeForPc --
 *
 *	Given a program counter value, return the closest enclosing
 *	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
 *	ExceptionRange is found that encloses pc, a NULL is returned.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static ExceptionRange *
GetExceptRangeForPc(
    unsigned char *pc,		/* The program counter value for which to
				 * 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
				 * consider only catch ranges (and ignore any
				 * closer loop ranges). */


    ByteCode *codePtr)		/* Points to the ByteCode in which to search
				 * for the enclosing ExceptionRange. */
{
    ExceptionRange *rangeArrayPtr;
    int numRanges = codePtr->numExceptRanges;
    register ExceptionRange *rangePtr;
    int pcOffset = pc - codePtr->codeStart;







>
>
|
|
|
<
<
>
|
|














|
|

|
>
>







7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951


7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
 *
 * GetExceptRangeForPc --
 *
 *	Given a program counter value, return the closest enclosing
 *	ExceptionRange.
 *
 * Results:
 *	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:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static ExceptionRange *
GetExceptRangeForPc(
    unsigned char *pc,		/* The program counter value for which to
				 * search for a closest enclosing exception
				 * range. This points to a bytecode
				 * instruction in codePtr's code. */
    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). 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. */
{
    ExceptionRange *rangeArrayPtr;
    int numRanges = codePtr->numExceptRanges;
    register ExceptionRange *rangePtr;
    int pcOffset = pc - codePtr->codeStart;
7990
7991
7992
7993
7994
7995
7996
7997
7998






7999
8000
8001
8002
8003
8004
8005

    rangeArrayPtr = codePtr->exceptArrayPtr;
    rangePtr = rangeArrayPtr + numRanges;
    while (--rangePtr >= rangeArrayPtr) {
	start = rangePtr->codeOffset;
	if ((start <= pcOffset) &&
		(pcOffset < (start + rangePtr->numCodeBytes))) {
	    if ((!catchOnly)
		    || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {






		return rangePtr;
	    }
	}
    }
    return NULL;
}








<
|
>
>
>
>
>
>







7993
7994
7995
7996
7997
7998
7999

8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013

    rangeArrayPtr = codePtr->exceptArrayPtr;
    rangePtr = rangeArrayPtr + numRanges;
    while (--rangePtr >= rangeArrayPtr) {
	start = rangePtr->codeOffset;
	if ((start <= pcOffset) &&
		(pcOffset < (start + rangePtr->numCodeBytes))) {

	    if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
		return rangePtr;
	    }
	    if (searchMode == TCL_BREAK) {
		return rangePtr;
	    }
	    if (searchMode == TCL_CONTINUE && rangePtr->continueOffset != -1){
		return rangePtr;
	    }
	}
    }
    return NULL;
}


Changes to tests/for.test.

806
807
808
809
810
811
812






































































































































































813
814
815
816
817
    1 {invoked "break" outside of a loop} \
    1 {invoked "continue" outside of a loop} \
    1 {invoked "break" outside of a loop} \
    1 {invoked "continue" outside of a loop} \
    0 {} \
    1 {invoked "continue" outside of a loop} \
    ]








































































































































































# cleanup
::tcltest::cleanupTests
return







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
    1 {invoked "break" outside of a loop} \
    1 {invoked "continue" outside of a loop} \
    1 {invoked "break" outside of a loop} \
    1 {invoked "continue" outside of a loop} \
    0 {} \
    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
return