summaryrefslogtreecommitdiffstats
path: root/tests/compile.test
diff options
context:
space:
mode:
Diffstat (limited to 'tests/compile.test')
-rw-r--r--tests/compile.test443
1 files changed, 421 insertions, 22 deletions
diff --git a/tests/compile.test b/tests/compile.test
index 5e81a5c..7646c12 100644
--- a/tests/compile.test
+++ b/tests/compile.test
@@ -1,4 +1,5 @@
-# This file contains tests for the files tclCompile.c and tclCompCmds.c
+# This file contains tests for the files tclCompile.c, tclCompCmds.c
+# and tclLiteral.c
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands. Sourcing this file into Tcl runs the tests and
@@ -9,13 +10,13 @@
#
# 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.11 2001/08/31 17:53:57 hobbs Exp $
-if {[lsearch [namespace children] ::tcltest] == -1} {
- package require tcltest
- namespace import -force ::tcltest::*
-}
+package require tcltest 2
+namespace import -force ::tcltest::*
+
+testConstraint exec [llength [info commands exec]]
+testConstraint memory [llength [info commands memory]]
+testConstraint testevalex [llength [info commands testevalex]]
# The following tests are very incomplete, although the rest of the
# test suite covers this file fairly well.
@@ -71,6 +72,15 @@ test compile-2.4 {TclCompileDollarVar: global scalar name with ::s} {
}
list [p] $::a(1) [expr {[lsearch -exact [info globals] a] != 0}]
} {1 1 1}
+test compile-2.5 {TclCompileDollarVar: global array, called as ${arrName(0)}} {
+ catch {unset a}
+ proc p {} {
+ global a
+ set a(1) 1
+ return ${a(1)}$::a(1)$a(1)
+ }
+ list [p] $::a(1) [expr {[lsearch -exact [info globals] a] != 0}]
+} {111 1 1}
test compile-3.1 {TclCompileCatchCmd: only catch cmds with scalar vars are compiled inline} {
catch {unset a}
@@ -97,6 +107,55 @@ test compile-3.3 {TclCompileCatchCmd: overagressive compiling [bug 219184]} {
catch {catch-test error} ::foo
set ::foo
} {GOOD}
+test compile-3.4 {TclCompileCatchCmd: bcc'ed [return] is caught} {
+ proc foo {} {
+ set fail [catch {
+ return 1
+ }] ; # {}
+ return 2
+ }
+ foo
+} {2}
+test compile-3.5 {TclCompileCatchCmd: recover from error, [Bug 705406]} {
+ proc foo {} {
+ catch {
+ if {[a]} {
+ if b {}
+ }
+ }
+ }
+ 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
@@ -205,40 +264,380 @@ test compile-11.1 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
lindex a bogus
}
list [catch {p} msg] $msg
-} {1 {bad index "bogus": must be integer or end?-integer?}}
+} {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}}
test compile-11.2 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
proc p {} { set r [list foobar] ; string index a bogus }
list [catch {p} msg] $msg
-} {1 {bad index "bogus": must be integer or end?-integer?}}
-test compile-11.3 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
- proc p {} { set r [list foobar] ; string index a 09 }
+} {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}}
+test compile-11.3 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
+ proc p {} { set r [list foobar] ; string index a 0o9 }
list [catch {p} msg] $msg
-} {1 {bad index "09": must be integer or end?-integer? (looks like invalid octal number)}}
+} -match glob -result {1 {*invalid octal number*}}
test compile-11.4 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
proc p {} { set r [list foobar] ; array set var {one two many} }
list [catch {p} msg] $msg
} {1 {list must have an even number of elements}}
test compile-11.5 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
- proc p {} { set r [list foobar] ; incr foo }
+ proc p {} { set r [list foobar] ; incr foo bar baz}
list [catch {p} msg] $msg
-} {1 {can't read "foo": no such variable}}
+} {1 {wrong # args: should be "incr varName ?increment?"}}
test compile-11.6 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
- proc p {} { set r [list foobar] ; incr foo bogus }
+ proc p {} { set r [list foobar] ; incr}
list [catch {p} msg] $msg
-} {1 {expected integer but got "bogus"}}
-test compile-11.7 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
+} {1 {wrong # args: should be "incr varName ?increment?"}}
+test compile-11.7 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
proc p {} { set r [list foobar] ; expr !a }
- list [catch {p} msg] $msg
-} {1 {syntax error in expression "!a"}}
-test compile-11.8 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
+ p
+} -returnCodes error -match glob -result *
+test compile-11.8 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
proc p {} { set r [list foobar] ; expr {!a} }
- list [catch {p} msg] $msg
-} {1 {syntax error in expression "!a"}}
+ p
+} -returnCodes error -match glob -result *
test compile-11.9 {Tcl_Append*: ensure Tcl_ResetResult is used properly} {
proc p {} { set r [list foobar] ; llength "\{" }
list [catch {p} msg] $msg
} {1 {unmatched open brace in list}}
+#
+# Special section for tests of tclLiteral.c
+# The following tests check for incorrect memory handling in
+# TclReleaseLiteral. They are only effective when tcl is compiled
+# with TCL_MEM_DEBUG
+#
+# Special test for leak on interp delete [Bug 467523].
+test compile-12.1 {testing literal leak on interp delete} -setup {
+ proc getbytes {} {
+ set lines [split [memory info] "\n"]
+ lindex $lines 3 3
+ }
+} -constraints memory -body {
+ set end [getbytes]
+ for {set i 0} {$i < 5} {incr i} {
+ interp create foo
+ foo eval {
+ namespace eval bar {}
+ }
+ interp delete foo
+ set tmp $end
+ set end [getbytes]
+ }
+ set leakedBytes [expr {$end - $tmp}]
+} -cleanup {
+ rename getbytes {}
+ unset -nocomplain end i tmp leakedBytes
+} -result 0
+# Special test for a memory error in a preliminary fix of [Bug 467523].
+# It requires executing a helpfile. Presumably the child process is
+# used because when this test fails, it crashes.
+test compile-12.2 {testing error on literal deletion} -constraints {memory exec} -body {
+ set sourceFile [makeFile {
+ for {set i 0} {$i < 5} {incr i} {
+ namespace eval bar {}
+ namespace delete bar
+ }
+ puts 0
+ } source.file]
+ exec [interpreter] $sourceFile
+} -cleanup {
+ catch {removeFile $sourceFile}
+} -result 0
+# Test to catch buffer overrun in TclCompileTokens from buf 530320
+test compile-12.3 {check for a buffer overrun} -body {
+ proc crash {} {
+ puts $array([expr {a+2}])
+ }
+ crash
+} -returnCodes error -cleanup {
+ rename crash {}
+} -match glob -result *
+test compile-12.4 {TclCleanupLiteralTable segfault} -body {
+ # Tcl Bug 1001997
+ # Here, we're trying to test a case that causes a crash in
+ # TclCleanupLiteralTable. The conditions that we're trying to
+ # establish are:
+ # - TclCleanupLiteralTable is attempting to clean up a bytecode
+ # object in the literal table.
+ # - The bytecode object in question contains the only reference
+ # to another literal.
+ # - The literal in question is in the same hash bucket as the bytecode
+ # object, and immediately follows it in the chain.
+ # Since newly registered literals are added at the FRONT of the
+ # bucket chains, and since the bytecode object is registered before
+ # its literals, this is difficult to achieve. What we do is:
+ # (a) do a [namespace eval] of a string that's calculated to
+ # hash into the same bucket as a literal that it contains.
+ # In this case, the script and the variable 'bugbug'
+ # land in the same bucket.
+ # (b) do a [namespace eval] of a string that contains enough
+ # literals to force TclRegisterLiteral to rebuild the global
+ # literal table. The newly created hash buckets will contain
+ # the literals, IN REVERSE ORDER, thus putting the bytecode
+ # immediately ahead of 'bugbug' and 'bug4345bug'. The bytecode
+ # object will contain the only references to those two literals.
+ # (c) Delete the interpreter to invoke TclCleanupLiteralTable
+ # and tickle the bug.
+ proc foo {} {
+ set i [interp create]
+ $i eval {
+ namespace eval ::w {concat 4649; variable bugbug}
+ namespace eval ::w {
+ concat x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 \
+ x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 \
+ x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 \
+ x31 x32 X33 X34 X35 X36 X37 X38 X39 X40 \
+ x41 x42 x43 x44 x45 x46 x47 x48 x49 x50 \
+ x51 x52 x53 x54 x55 x56 x57 x58 x59 x60 \
+ x61 x62 x63 x64
+ concat y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 \
+ y11 y12 y13 y14 y15 y16 y17 y18 y19 y20 \
+ y21 y22 y23 y24 y25 y26 y27 y28 y29 y30 \
+ y31 y32 Y33 Y34 Y35 Y36 Y37 Y38 Y39 Y40 \
+ y41 y42 y43 y44 y45 y46 y47 y48 y49 y50 \
+ y51 y52 y53 y54 y55 y56 y57 y58 y59 y60 \
+ y61 y62 y63 y64
+ concat z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 \
+ z11 z12 z13 z14 z15 z16 z17 z18 z19 z20 \
+ z21 z22 z23 z24 z25 z26 z27 z28 z29 z30 \
+ z31 z32
+ }
+ }
+ interp delete $i; # must not crash
+ return ok
+ }
+ foo
+} -cleanup {
+ rename foo {}
+} -result ok
+
+# Special test for underestimating the maxStackSize required for a
+# compiled command. A failure will cause a segfault in the child
+# process.
+test compile-13.1 {testing underestimate of maxStackSize in list cmd} {exec} {
+ set body {set x [list}
+ for {set i 0} {$i < 3000} {incr i} {
+ append body " $i"
+ }
+ append body {]; puts OK}
+ regsub BODY {proc crash {} {BODY}; crash} $body script
+ list [catch {exec [interpreter] << $script} msg] $msg
+} {0 OK}
+
+# Tests compile-14.* for [Bug 599788] [Bug 0c043a175a47da8c2342]
+test compile-14.1 {testing errors in element name; segfault?} {} {
+ catch {set a([error])} msg1
+ catch {set bubba([join $abba $jubba]) $vol} msg2
+ list $msg1 $msg2
+} {{wrong # args: should be "error message ?errorInfo? ?errorCode?"} {can't read "abba": no such variable}}
+
+test compile-14.2 {testing element name "$"} -body {
+ unset -nocomplain a
+ set a() 1
+ set a(1) 2
+ set a($) 3
+ list [set a()] [set a(1)] [set a($)] [unset a() a(1); lindex [array names a] 0]
+} -cleanup {unset a} -result [list 1 2 3 {$}]
+
+
+# Tests compile-15.* cover Tcl Bug 633204
+test compile-15.1 {proper TCL_RETURN code from [return]} {
+ proc p {} {catch return}
+ set result [p]
+ rename p {}
+ set result
+} 2
+test compile-15.2 {proper TCL_RETURN code from [return]} {
+ proc p {} {catch {return foo}}
+ set result [p]
+ rename p {}
+ set result
+} 2
+test compile-15.3 {proper TCL_RETURN code from [return]} {
+ proc p {} {catch {return $::tcl_library}}
+ set result [p]
+ rename p {}
+ set result
+} 2
+test compile-15.4 {proper TCL_RETURN code from [return]} {
+ proc p {} {catch {return [info library]}}
+ set result [p]
+ rename p {}
+ set result
+} 2
+test compile-15.5 {proper TCL_RETURN code from [return]} {
+ proc p {} {catch {set a 1}; return}
+ set result [p]
+ rename p {}
+ set result
+} ""
+
+for {set noComp 0} {$noComp <= 1} {incr noComp} {
+
+if $noComp {
+ interp alias {} run {} testevalex
+ set constraints testevalex
+} else {
+ interp alias {} run {} if 1
+ set constraints {}
+}
+
+test compile-16.1.$noComp {TclCompileScript: word expansion} $constraints {
+ run "list [string repeat {{*}a } 255]"
+} [lrepeat 255 a]
+test compile-16.2.$noComp {TclCompileScript: word expansion} $constraints {
+ run "list [string repeat {{*}a } 256]"
+} [lrepeat 256 a]
+test compile-16.3.$noComp {TclCompileScript: word expansion} $constraints {
+ run "list [string repeat {{*}a } 257]"
+} [lrepeat 257 a]
+test compile-16.4.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list}
+} {}
+test compile-16.5.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list {*}{x y z}}
+} {x y z}
+test compile-16.6.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list {*}[list x y z]}
+} {x y z}
+test compile-16.7.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list {*}[list x y z][list x y z]}
+} {x y zx y z}
+test compile-16.8.$noComp {TclCompileScript: word expansion} -body {
+ set l {x y z}
+ run {{*}list {*}$l}
+} -constraints $constraints -cleanup {
+ unset l
+} -result {x y z}
+test compile-16.9.$noComp {TclCompileScript: word expansion} -body {
+ set l {x y z}
+ run {{*}list {*}$l$l}
+} -constraints $constraints -cleanup {
+ unset l
+} -result {x y zx y z}
+test compile-16.10.$noComp {TclCompileScript: word expansion} -body {
+ run {{*}\{}
+} -constraints $constraints -returnCodes error \
+-result {unmatched open brace in list}
+test compile-16.11.$noComp {TclCompileScript: word expansion} -body {
+ proc badList {} {return \{}
+ run {{*}[badList]}
+} -constraints $constraints -cleanup {
+ rename badList {}
+} -returnCodes error -result {unmatched open brace in list}
+test compile-16.12.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list x y z}
+} {x y z}
+test compile-16.13.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list x y {*}z}
+} {x y z}
+test compile-16.14.$noComp {TclCompileScript: word expansion} $constraints {
+ run {{*}list x {*}y z}
+} {x y z}
+test compile-16.15.$noComp {TclCompileScript: word expansion} $constraints {
+ run {list x y {*}z}
+} {x y z}
+test compile-16.16.$noComp {TclCompileScript: word expansion} $constraints {
+ run {list x {*}y z}
+} {x y z}
+test compile-16.17.$noComp {TclCompileScript: word expansion} $constraints {
+ run {list {*}x y z}
+} {x y z}
+
+# These tests note that expansion can in theory cause the number of
+# arguments to a command to exceed INT_MAX, which is as big as objc
+# is allowed to get.
+#
+# In practice, it seems we will run out of memory before we confront
+# this issue. Note that compiled operations run out of memory at
+# smaller objc values than direct string evaluation.
+#
+# These tests are constrained as knownBug because they are likely
+# to cause memory allocation panics somewhere, and we don't want
+# panics in the test suite.
+#
+test compile-16.18.$noComp {TclCompileScript: word expansion} -body {
+ proc LongList {} {return [lrepeat [expr {1<<10}] x]}
+ llength [run "list [string repeat {{*}[LongList] } [expr {1<<10}]]"]
+} -constraints [linsert $constraints 0 knownBug] -cleanup {
+ rename LongList {}
+} -returnCodes ok -result [expr {1<<20}]
+test compile-16.19.$noComp {TclCompileScript: word expansion} -body {
+ proc LongList {} {return [lrepeat [expr {1<<11}] x]}
+ llength [run "list [string repeat {{*}[LongList] } [expr {1<<11}]]"]
+} -constraints [linsert $constraints 0 knownBug] -cleanup {
+ rename LongList {}
+} -returnCodes ok -result [expr {1<<22}]
+test compile-16.20.$noComp {TclCompileScript: word expansion} -body {
+ proc LongList {} {return [lrepeat [expr {1<<12}] x]}
+ llength [run "list [string repeat {{*}[LongList] } [expr {1<<12}]]"]
+} -constraints [linsert $constraints 0 knownBug] -cleanup {
+ rename LongList {}
+} -returnCodes ok -result [expr {1<<24}]
+# This is the one that should cause overflow
+test compile-16.21.$noComp {TclCompileScript: word expansion} -body {
+ proc LongList {} {return [lrepeat [expr {1<<16}] x]}
+ llength [run "list [string repeat {{*}[LongList] } [expr {1<<16}]]"]
+} -constraints [linsert $constraints 0 knownBug] -cleanup {
+ rename LongList {}
+} -returnCodes ok -result [expr {wide(1)<<32}]
+test compile-16.22.$noComp {
+ Bug 845412: TclCompileScript: word expansion not mandatory
+} -body {
+ # This test may crash and will fail unless Bug 845412 is fixed.
+ proc ReturnResults args {return $args}
+ run "ReturnResults [string repeat {x } 260]"
+} -constraints $constraints -cleanup {
+ rename ReturnResults {}
+} -returnCodes ok -result [string trim [string repeat {x } 260]]
+test compile-16.23.$noComp {
+ Bug 1032805: defer parse error until run time
+} -constraints $constraints -body {
+ namespace eval x {
+ run {
+ proc if {a b} {uplevel 1 [list set $a $b]}
+ if 1 {syntax {}{}}
+ }
+ }
+} -cleanup {
+ namespace delete x
+} -returnCodes ok -result {syntax {}{}}
+test compile-16.24.$noComp {
+ Bug 1638414: bad list constant as first expanded term
+} -constraints $constraints -body {
+ run "{*}\"\{foo bar\""
+} -returnCodes error -result {unmatched open brace in list}
+} ;# End of noComp loop
+
+# These tests are messy because it wrecks the interpreter it runs in!
+# They demonstrate issues arising from [FRQ 1101710]
+test compile-17.1 {Command interpretation binding for compiled code} -constraints knownBug -setup {
+ set i [interp create]
+} -body {
+ $i eval {
+ if 1 {
+ expr [
+ proc expr args {return substituted}
+ format {[subst compiled]}
+ ]
+ }
+ }
+} -cleanup {
+ interp delete $i
+} -result substituted
+test compile-17.2 {Command interpretation binding for non-compiled code} -setup {
+ set i [interp create]
+} -body {
+ $i eval {
+ if 1 {
+ [subst expr] [
+ proc expr args {return substituted}
+ format {[subst compiled]}
+ ]
+ }
+ }
+} -cleanup {
+ interp delete $i
+} -result substituted
+
# cleanup
catch {rename p ""}
catch {namespace delete test_ns_compile}