From 03a3c09b1fc4fc80caec28b88b0fe09d612835b8 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Tue, 19 Jun 2018 11:47:08 +0000 Subject: new file: tools/valgrind_suppress. num-callers bumped from 8 to 24. Valgrind now issues no "still reachable" reports for cmdAH.test. --- tests/all.tcl | 23 ++++++++++++++--------- tests/pkgIndex.tcl | 2 +- tools/valgrind_suppress | 33 +++++++++++++++++++++++++++++++++ unix/Makefile.in | 4 +++- 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 tools/valgrind_suppress diff --git a/tests/all.tcl b/tests/all.tcl index ad372db..d6434fb 100644 --- a/tests/all.tcl +++ b/tests/all.tcl @@ -14,18 +14,23 @@ package prefer latest package require Tcl 8.5- package require tcltest 2.2 namespace import tcltest::* -configure {*}$argv -testdir [file dir [info script]] -if {[singleProcess]} { - interp debug {} -frame 1 -} -set testsdir [file dirname [file dirname [file normalize [info script]/...]]] -lappend auto_path $testsdir {*}[apply {{testsdir args} { - lmap x $args { +apply {args { + global auto_path + set testsdir [file dirname [file dirname [file normalize [ + info script]/...]]] + + configure {*}$args -testdir $testsdir + + if {[singleProcess]} { + interp debug {} -frame 1 + } + + set auto_path [lmap x $auto_path[set auto_path {}] { if {$x eq $testsdir} continue lindex $x - } -}} $testsdir {*}$auto_path] + }] +}} {*}$argv runAllTests proc exit args {} diff --git a/tests/pkgIndex.tcl b/tests/pkgIndex.tcl index 0feb0eb..854b943 100644 --- a/tests/pkgIndex.tcl +++ b/tests/pkgIndex.tcl @@ -1,6 +1,6 @@ #! /usr/bin/env tclsh package ifneeded tcltests 0.1 " - source [list $dir]/tcltests.tcl + source [list $dir/tcltests.tcl] package provide tcltests 0.1 " diff --git a/tools/valgrind_suppress b/tools/valgrind_suppress new file mode 100644 index 0000000..e8f0204 --- /dev/null +++ b/tools/valgrind_suppress @@ -0,0 +1,33 @@ +{ + TclpGetPwNam/getpwname_r/__nss_next2/calloc + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:__nss_next2 + ... + fun:TclpGetPwNam +} + +{ + TclpGetPwNam/getpwname_r/__nss_next2/malloc + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:__nss_next2 + ... + fun:TclpGetPwNam +} + +{ + TclpGetPwNam/getpwname_r/_nss_systemd_getpwnam_r/malloc + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:_nss_systemd_getpwnam_r + ... + fun:TclpGetPwNam +} + diff --git a/unix/Makefile.in b/unix/Makefile.in index 4277fad..060148f 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -262,7 +262,9 @@ GDB = gdb TRACE = strace TRACE_OPTS = VALGRIND = valgrind -VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high --leak-check=yes --show-reachable=yes -v +VALGRINDARGS = --tool=memcheck --num-callers=24 \ + --leak-resolution=high --leak-check=yes --show-reachable=yes -v \ + --suppressions=$(TOOL_DIR)/valgrind_suppress #-------------------------------------------------------------------------- # The information below should be usable as is. The configure script won't -- cgit v0.12 From 645241afc13d0aa6272925a04c3afa93ca93ef19 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Jun 2018 08:03:22 +0000 Subject: Remove recent auto_path modification in tests/all.tcl and suppress more valgrind reports. --- tests/all.tcl | 20 +++++--------------- tools/valgrind_suppress | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/all.tcl b/tests/all.tcl index d6434fb..250163b 100644 --- a/tests/all.tcl +++ b/tests/all.tcl @@ -15,22 +15,12 @@ package require Tcl 8.5- package require tcltest 2.2 namespace import tcltest::* -apply {args { - global auto_path - set testsdir [file dirname [file dirname [file normalize [ - info script]/...]]] +configure {*}$argv -testdir [file dirname [file dirname [file normalize [ + info script]/...]]] - configure {*}$args -testdir $testsdir - - if {[singleProcess]} { - interp debug {} -frame 1 - } - - set auto_path [lmap x $auto_path[set auto_path {}] { - if {$x eq $testsdir} continue - lindex $x - }] -}} {*}$argv +if {[singleProcess]} { + interp debug {} -frame 1 +} runAllTests proc exit args {} diff --git a/tools/valgrind_suppress b/tools/valgrind_suppress index e8f0204..84ed4cd 100644 --- a/tools/valgrind_suppress +++ b/tools/valgrind_suppress @@ -31,3 +31,23 @@ fun:TclpGetPwNam } +{ + TclCreatesocketAddress/getaddrinfo/calloc + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:getaddrinfo + fun:TclCreateSocketAddress +} + +{ + TclCreatesocketAddress/getaddrinfo/malloc + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:getaddrinfo + fun:TclCreateSocketAddress +} + -- cgit v0.12 From c911dc937fb03f387cc7ecd74b04a2e60ddb53b5 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Jun 2018 19:06:40 +0000 Subject: Add valgrind suppression for dlopen and ensure that processes are reaped in http11.test. --- tests/http11.test | 7 +++++++ tools/valgrind_suppress | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/tests/http11.test b/tests/http11.test index c9ded0b..2e50837 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -666,6 +666,13 @@ test http11-4.3 "normal post request, check channel query length" -setup { # ------------------------------------------------------------------------- +# Eliminate valgrind "still reachable" reports on outstanding "Detached" +# structures in the detached list which stem from PipeClose2Proc not waiting +# around for background processes to complete, meaning that previous calls to +# Tcl_ReapDetachedProcs might not have had a chance to reap all processes. +after 10 +exec [info nameofexecutable] << {} + foreach p {create_httpd httpd_read halt_httpd meta check_crc} { if {[llength [info proc $p]]} {rename $p {}} } diff --git a/tools/valgrind_suppress b/tools/valgrind_suppress index 84ed4cd..3c733c2 100644 --- a/tools/valgrind_suppress +++ b/tools/valgrind_suppress @@ -51,3 +51,13 @@ fun:TclCreateSocketAddress } +{ + TclpDlopen/load + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:dlopen + fun:TclpDlopen +} + -- cgit v0.12 From 107fb1eb331d7f346dfbdf5e7655a28f4643899c Mon Sep 17 00:00:00 2001 From: pooryorick Date: Thu, 21 Jun 2018 22:16:29 +0000 Subject: Suppress more valgrind "still reachable" reports and ensure that threads are fully finalized in thread tests. --- tests/thread.test | 56 +++++++++++++++++++------------ tools/valgrind_suppress | 87 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 106 insertions(+), 37 deletions(-) diff --git a/tests/thread.test b/tests/thread.test index cc4c871..a23670a 100644 --- a/tests/thread.test +++ b/tests/thread.test @@ -11,17 +11,22 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +# when thread::release is used, -wait is passed in order allow the thread to +# be fully finalized, which avoids valgrind "still reachable" reports. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.2 namespace import -force ::tcltest::* } +package require tcltests + ::tcltest::loadTestedCommands catch [list package require -exact Tcltest [info patchlevel]] # Some tests require the testthread command -testConstraint testthread [expr {[info commands testthread] != {}}] +testConstraint testthread [expr {[info commands testthread] ne {}}] # Some tests require the Thread package @@ -72,6 +77,17 @@ proc ThreadError {id info} { set threadSawError($id) true; # signal main thread to exit [vwait]. } +proc threadSuperKill id { + variable threadSuperKillScript + try { + thread::send $id $::threadSuperKillScript + } on error {tres topts} { + if {$tres ne {target thread died}} { + return -options $topts $tres + } + } +} + if {[testConstraint thread]} { thread::errorproc ThreadError } @@ -96,22 +112,22 @@ test thread-1.3 {Tcl_ThreadObjCmd: initial thread list} {thread} { test thread-1.4 {Tcl_ThreadObjCmd: thread create } {thread} { set serverthread [thread::create -preserved] set numthreads [llength [thread::names]] - thread::release $serverthread + thread::release -wait $serverthread set numthreads -} {2} +} 2 test thread-1.5 {Tcl_ThreadObjCmd: thread create one shot} {thread} { thread::create {set x 5} foreach try {0 1 2 4 5 6} { - # Try various ways to yield - update - after 10 - set l [llength [thread::names]] - if {$l == 1} { - break - } + # Try various ways to yield + update + after 10 + set l [llength [thread::names]] + if {$l == 1} { + break + } } set l -} {1} +} 1 test thread-1.6 {Tcl_ThreadObjCmd: thread exit} {thread} { thread::create {{*}{}} update @@ -121,13 +137,13 @@ test thread-1.6 {Tcl_ThreadObjCmd: thread exit} {thread} { test thread-1.13 {Tcl_ThreadObjCmd: send args} {thread} { set serverthread [thread::create -preserved] set five [thread::send $serverthread {set x 5}] - thread::release $serverthread + thread::release -wait $serverthread set five } 5 test thread-1.15 {Tcl_ThreadObjCmd: wait} {thread} { set serverthread [thread::create -preserved {set z 5 ; thread::wait}] set five [thread::send $serverthread {set z}] - thread::release $serverthread + thread::release -wait $serverthread set five } 5 @@ -159,7 +175,7 @@ test thread-3.1 {TclThreadList} {thread} { set l2 [thread::names] set c [string compare [lsort [concat [thread::id] $l1]] [lsort $l2]] foreach t $l1 { - thread::release $t + thread::release -wait $t } list $len $c } {1 0} @@ -887,7 +903,7 @@ test thread-7.24 {cancel: nested catch inside pure bytecode loop} {thread drainE # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::cancel $serverthread] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ @@ -929,7 +945,7 @@ test thread-7.25 {cancel: nested catch inside pure inside-command loop} {thread # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::cancel $serverthread] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ @@ -1029,7 +1045,7 @@ test thread-7.28 {cancel: send async cancel nested catch inside pure bytecode lo # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::send -async $serverthread {interp cancel}] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ @@ -1071,7 +1087,7 @@ test thread-7.29 {cancel: send async cancel nested catch pure inside-command loo # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::send -async $serverthread {interp cancel}] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ @@ -1111,7 +1127,7 @@ test thread-7.30 {cancel: send async thread cancel nested catch inside pure byte # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::send -async $serverthread {thread::cancel [thread::id]}] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ @@ -1153,7 +1169,7 @@ test thread-7.31 {cancel: send async thread cancel nested catch pure inside-comm # wait for other thread to signal "ready to cancel" vwait ::threadIdStarted; after 1000 set res [thread::send -async $serverthread {thread::cancel [thread::id]}] - thread::send $serverthread $::threadSuperKillScript + threadSuperKill $serverthread vwait ::threadSawError($serverthread) thread::join $serverthread; drainEventQueue list $res [expr {[info exists ::threadIdStarted] ? \ diff --git a/tools/valgrind_suppress b/tools/valgrind_suppress index 3c733c2..ede584a 100644 --- a/tools/valgrind_suppress +++ b/tools/valgrind_suppress @@ -1,63 +1,116 @@ { - TclpGetPwNam/getpwname_r/__nss_next2/calloc + TclCreatesocketAddress/getaddrinfo/calloc + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:getaddrinfo + fun:TclCreateSocketAddress +} + +{ + TclCreatesocketAddress/getaddrinfo/malloc + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:getaddrinfo + fun:TclCreateSocketAddress +} + +{ + TclpDlopen/load + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:dlopen + fun:TclpDlopen +} + +{ + TclpGetGrNam/__nss_next2/calloc Memcheck:Leak match-leak-kinds: reachable fun:calloc ... fun:__nss_next2 ... - fun:TclpGetPwNam + fun:TclpGetGrNam } { - TclpGetPwNam/getpwname_r/__nss_next2/malloc + TclpGetGrNam/__nss_next2/malloc Memcheck:Leak match-leak-kinds: reachable fun:malloc ... fun:__nss_next2 ... - fun:TclpGetPwNam + fun:TclpGetGrNam } { - TclpGetPwNam/getpwname_r/_nss_systemd_getpwnam_r/malloc + TclpGetGrNam/__nss_systemd_getfrname_r/malloc Memcheck:Leak match-leak-kinds: reachable fun:malloc ... - fun:_nss_systemd_getpwnam_r + fun:_nss_systemd_getgrnam_r ... - fun:TclpGetPwNam + fun:TclpGetGrNam } { - TclCreatesocketAddress/getaddrinfo/calloc + TclpGetPwNam/getpwname_r/__nss_next2/calloc Memcheck:Leak match-leak-kinds: reachable fun:calloc ... - fun:getaddrinfo - fun:TclCreateSocketAddress + fun:__nss_next2 + ... + fun:TclpGetPwNam } { - TclCreatesocketAddress/getaddrinfo/malloc + TclpGetPwNam/getpwname_r/__nss_next2/malloc Memcheck:Leak match-leak-kinds: reachable fun:malloc ... - fun:getaddrinfo - fun:TclCreateSocketAddress + fun:__nss_next2 + ... + fun:TclpGetPwNam } { - TclpDlopen/load + TclpGetPwNam/getpwname_r/_nss_systemd_getpwnam_r/malloc Memcheck:Leak match-leak-kinds: reachable - fun:calloc + fun:malloc ... - fun:dlopen - fun:TclpDlopen + fun:_nss_systemd_getpwnam_r + ... + fun:TclpGetPwNam +} + +{ + TclpThreadExit/pthread_exit/calloc + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + ... + fun:pthread_exit + fun:TclpThreadExit +} + +{ + TclpThreadExit/pthread_exit/malloc + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:pthread_exit + fun:TclpThreadExit } -- cgit v0.12 From 56ca35e8a95b8cfaac73104d3699c2b901298a2d Mon Sep 17 00:00:00 2001 From: pooryorick Date: Thu, 21 Jun 2018 22:21:31 +0000 Subject: Add custom exit procedure for tcltests executable. --- generic/tclInt.h | 1 + generic/tclTest.c | 16 ++++++++++++++++ generic/tclThreadTest.c | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/generic/tclInt.h b/generic/tclInt.h index 0a3285f..6fc2e85 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4532,6 +4532,7 @@ MODULE_SCOPE Tcl_PackageInitProc TclObjTest_Init; MODULE_SCOPE Tcl_PackageInitProc TclThread_Init; MODULE_SCOPE Tcl_PackageInitProc Procbodytest_Init; MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; +MODULE_SCOPE void *TclThreadTestFinalize(); /* *---------------------------------------------------------------- diff --git a/generic/tclTest.c b/generic/tclTest.c index 45cca5a..952f384 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -52,6 +52,7 @@ #define TCL_STORAGE_CLASS DLLEXPORT EXTERN int Tcltest_Init(Tcl_Interp *interp); EXTERN int Tcltest_SafeInit(Tcl_Interp *interp); +EXTERN TCL_NORETURN void Tcltest_Exit(ClientData clientData); /* * Dynamic string shared by TestdcallCmd and DelCallbackProc; used to collect @@ -563,6 +564,10 @@ Tcltest_Init( return TCL_ERROR; } + + /* Finalizer */ + Tcl_SetExitProc(Tcltest_Exit); + /* * Create additional commands and math functions for testing Tcl. */ @@ -790,6 +795,17 @@ Tcltest_SafeInit( return Procbodytest_SafeInit(interp); } +TCL_NORETURN void Tcltest_Exit( + ClientData clientData +) { + int status = PTR2INT(clientData); + Tcl_Finalize(); + TclThreadTestFinalize(); + TclpExit(status); + Tcl_Panic("OS exit failed!"); +} + + /* *---------------------------------------------------------------------- * diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index 6fc0e52..3d63964 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -176,6 +176,13 @@ TclThread_Init( } +void * TclThreadTestFinalize() { + if (errorProcString != NULL) { + ckfree(errorProcString); + errorProcString= NULL; + } +} + /* *---------------------------------------------------------------------- * -- cgit v0.12 From 563bd6e4ddc1fab518dc16ebd1d39d05feffa6b0 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Thu, 21 Jun 2018 22:43:18 +0000 Subject: Fix function signature of TclThreadTestFinalize. --- generic/tclInt.h | 2 +- generic/tclThreadTest.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index 6fc2e85..64004d8 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4532,7 +4532,7 @@ MODULE_SCOPE Tcl_PackageInitProc TclObjTest_Init; MODULE_SCOPE Tcl_PackageInitProc TclThread_Init; MODULE_SCOPE Tcl_PackageInitProc Procbodytest_Init; MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; -MODULE_SCOPE void *TclThreadTestFinalize(); +MODULE_SCOPE void TclThreadTestFinalize(); /* *---------------------------------------------------------------- diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index 3d63964..92cfa13 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -176,11 +176,12 @@ TclThread_Init( } -void * TclThreadTestFinalize() { +void TclThreadTestFinalize() { if (errorProcString != NULL) { ckfree(errorProcString); errorProcString= NULL; } + return; } /* -- cgit v0.12 From 94ec3d943104b645666e3f71feb61ac260a43fcf Mon Sep 17 00:00:00 2001 From: pooryorick Date: Fri, 22 Jun 2018 15:10:04 +0000 Subject: Add another suppress rule for valgrind, factor test code into tests/tcltests.tcl, and constrained a some tests in the valgrind case. --- tests/all.tcl | 2 +- tests/chanio.test | 4 ---- tests/io.test | 4 ---- tests/ioCmd.test | 16 +++++++++++++--- tests/platform.test | 6 +++++- tests/tcltest.test | 7 +++++++ tests/tcltests.tcl | 12 ++++++++---- tests/thread.test | 11 ----------- tools/valgrind_suppress | 10 ++++++++++ 9 files changed, 44 insertions(+), 28 deletions(-) diff --git a/tests/all.tcl b/tests/all.tcl index 250163b..4fce323 100644 --- a/tests/all.tcl +++ b/tests/all.tcl @@ -13,7 +13,7 @@ package prefer latest package require Tcl 8.5- package require tcltest 2.2 -namespace import tcltest::* +namespace import -force ::tcltest::* configure {*}$argv -testdir [file dirname [file dirname [file normalize [ info script]/...]]] diff --git a/tests/chanio.test b/tests/chanio.test index 86c1485..492c11e 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -39,14 +39,10 @@ namespace eval ::tcl::test::io { catch [list package require -exact Tcltest [info patchlevel]] testConstraint testchannel [llength [info commands testchannel]] - testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 - testConstraint fileevent [llength [info commands fileevent]] - testConstraint fcopy [llength [info commands fcopy]] testConstraint testfevent [llength [info commands testfevent]] testConstraint testchannelevent [llength [info commands testchannelevent]] testConstraint testmainthread [llength [info commands testmainthread]] - testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # You need a *very* special environment to do some tests. In particular, # many file systems do not support large-files... diff --git a/tests/io.test b/tests/io.test index cdecb7b..cc1d986 100644 --- a/tests/io.test +++ b/tests/io.test @@ -36,14 +36,10 @@ namespace eval ::tcl::test::io { variable expected testConstraint testchannel [llength [info commands testchannel]] -testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 -testConstraint fileevent [llength [info commands fileevent]] -testConstraint fcopy [llength [info commands fcopy]] testConstraint testfevent [llength [info commands testfevent]] testConstraint testchannelevent [llength [info commands testchannelevent]] testConstraint testmainthread [llength [info commands testmainthread]] -testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] testConstraint testobj [llength [info commands testobj]] # You need a *very* special environment to do some tests. In diff --git a/tests/ioCmd.test b/tests/ioCmd.test index ae58025..948671e 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -21,10 +21,10 @@ if {[lsearch [namespace children] ::tcltest] == -1} { ::tcltest::loadTestedCommands catch [list package require -exact Tcltest [info patchlevel]] +package require tcltests + # Custom constraints used in this file -testConstraint fcopy [llength [info commands fcopy]] testConstraint testchannel [llength [info commands testchannel]] -testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] #---------------------------------------------------------------------- @@ -395,7 +395,7 @@ test iocmd-11.2 {I/O to command pipelines} {unixOrPc unixExecs} { test iocmd-11.3 {I/O to command pipelines} {unixOrPc unixExecs} { list [catch {open "| echo > \"$path(test5)\"" r+} msg] $msg $::errorCode } {1 {can't read output from command: standard output was redirected} {TCL OPERATION EXEC BADREDIRECT}} -test iocmd-11.4 {I/O to command pipelines} unixOrPc { +test iocmd-11.4 {I/O to command pipelines} {notValgrind unixOrPc} { list [catch {open "| no_such_command_exists" rb} msg] $msg $::errorCode } {1 {couldn't execute "no_such_command_exists": no such file or directory} {POSIX ENOENT {no such file or directory}}} @@ -3833,6 +3833,16 @@ test iocmd.tf-32.1 {origin thread of moved channel destroyed during access} -mat rename track {} # cleanup + + +# Eliminate valgrind "still reachable" reports on outstanding "Detached" +# structures in the detached list which stem from PipeClose2Proc not waiting +# around for background processes to complete, meaning that previous calls to +# Tcl_ReapDetachedProcs might not have had a chance to reap all processes. +after 10 +exec [info nameofexecutable] << {} + + foreach file [list test1 test2 test3 test4] { removeFile $file } diff --git a/tests/platform.test b/tests/platform.test index 8ee0ec7..e5a4c90 100644 --- a/tests/platform.test +++ b/tests/platform.test @@ -10,6 +10,7 @@ # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 +package require tcltests namespace eval ::tcl::test::platform { namespace import ::tcltest::testConstraint @@ -67,7 +68,10 @@ test platform-3.1 {CPU ID on Windows/UNIX} \ # format of string it produces consists of two non-empty words separated by a # hyphen. package require platform -test platform-4.1 {format of platform::identify result} -match regexp -body { +test platform-4.1 {format of platform::identify result} -constraints notValgrind -match regexp -body { + # [identify] may attempt to [exec] dpkg-architecture, which may not exist, + # in which case fork will not be followed by exec, and valgrind will issue + # "still reachable" reports. platform::identify } -result {^([^-]+-)+[^-]+$} test platform-4.2 {format of platform::generic result} -match regexp -body { diff --git a/tests/tcltest.test b/tests/tcltest.test index 17fa926..0bcf342 100644 --- a/tests/tcltest.test +++ b/tests/tcltest.test @@ -908,7 +908,9 @@ removeFile load.tcl # [interpreter] test tcltest-13.1 {interpreter} { + -constraints notValgrind -setup { + #to do: Why is $::tcltest::tcltest being saved and restored here? set old $::tcltest::tcltest set ::tcltest::tcltest tcltest } @@ -920,6 +922,11 @@ test tcltest-13.1 {interpreter} { } -result {tcltest tclsh tclsh} -cleanup { + # writing ::tcltest::tcltest triggers a trace that sets up the stdio + # constraint, which involves a call to [exec] that might fail after + # "fork" and before "exec", in which case the forked process will not + # have a chance to clean itself up before exiting, which causes + # valgrind to issue numerous "still reachable" reports. set ::tcltest::tcltest $old } } diff --git a/tests/tcltests.tcl b/tests/tcltests.tcl index 8d42b70..2105279 100644 --- a/tests/tcltests.tcl +++ b/tests/tcltests.tcl @@ -1,7 +1,11 @@ #! /usr/bin/env tclsh -# Some tests require the "exec" command. -# Skip them if exec is not defined. -testConstraint exec [llength [info commands exec]] +package require tcltest 2.2 +namespace import -force ::tcltest::* -testConstraint notValgrind [expr {![testConstraint valgrind]}] +testConstraint exec [llength [info commands exec]] +testConstraint fcopy [llength [info commands fcopy]] +testConstraint fileevent [llength [info commands fileevent]] +testConstraint thread [ + expr {0 == [catch {package require Thread 2.7-}]}] +testConstraint notValgrind [expr {![testConstraint valgrind]}] diff --git a/tests/thread.test b/tests/thread.test index a23670a..eaaaa41 100644 --- a/tests/thread.test +++ b/tests/thread.test @@ -14,10 +14,6 @@ # when thread::release is used, -wait is passed in order allow the thread to # be fully finalized, which avoids valgrind "still reachable" reports. -if {[lsearch [namespace children] ::tcltest] == -1} { - package require tcltest 2.2 - namespace import -force ::tcltest::* -} package require tcltests @@ -28,13 +24,6 @@ catch [list package require -exact Tcltest [info patchlevel]] testConstraint testthread [expr {[info commands testthread] ne {}}] -# Some tests require the Thread package - -testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] - -# Some tests may not work under valgrind - -testConstraint notValgrind [expr {![testConstraint valgrind]}] set threadSuperKillScript { rename catch "" diff --git a/tools/valgrind_suppress b/tools/valgrind_suppress index ede584a..fb7f173 100644 --- a/tools/valgrind_suppress +++ b/tools/valgrind_suppress @@ -29,6 +29,16 @@ } { + TclpDlopen/load + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + ... + fun:dlopen + fun:TclpDlopen +} + +{ TclpGetGrNam/__nss_next2/calloc Memcheck:Leak match-leak-kinds: reachable -- cgit v0.12 From 6cbfdcc4a338d5b7348ee7e65a7710d13f9bc27e Mon Sep 17 00:00:00 2001 From: pooryorick Date: Sat, 23 Jun 2018 14:18:06 +0000 Subject: Add a test for no generation of a string representation when comparing with the empty string. --- tests/expr.test | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/expr.test b/tests/expr.test index fd11870..a265ac6 100644 --- a/tests/expr.test +++ b/tests/expr.test @@ -7196,6 +7196,15 @@ test expr-51.1 {test round-to-even on input} { expr 6.9294956446009195e15 } 6929495644600920.0 +test expr-52.1 { + comparison with empty string does not generate string representation +} { + set a [list one two three] + list [expr {$a eq {}}] [expr {$a < {}}] [expr {$a > {}}] [ + string match {*no string representation*} [ + ::tcl::unsupported::representation $a]] +} {0 0 1 1} + # cleanup -- cgit v0.12 From e2a79c2604e79b36ec065a7bb44ec57eaca5ed8a Mon Sep 17 00:00:00 2001 From: pooryorick Date: Sun, 24 Jun 2018 07:17:46 +0000 Subject: Fix for [3592747]: Let TclNRTailcallEval handle namespace problems. --- generic/tclBasic.c | 8 +------- tests/tailcall.test | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 3ac3ffd..07f7e5c 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -8402,18 +8402,12 @@ TclNRTailcallObjCmd( if (objc > 1) { Tcl_Obj *listPtr, *nsObjPtr; Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr; - Tcl_Namespace *ns1Ptr; /* The tailcall data is in a Tcl list: the first element is the * namespace, the rest the command to be tailcalled. */ - listPtr = Tcl_NewListObj(objc, objv); - nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1); - if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr)) - || (nsPtr != ns1Ptr)) { - Tcl_Panic("Tailcall failed to find the proper namespace"); - } + listPtr = Tcl_NewListObj(objc, objv); TclListObjSetElement(interp, listPtr, 0, nsObjPtr); iPtr->varFramePtr->tailcallPtr = listPtr; diff --git a/tests/tailcall.test b/tests/tailcall.test index 26f3cbf..3751c35 100644 --- a/tests/tailcall.test +++ b/tests/tailcall.test @@ -688,6 +688,26 @@ if {[testConstraint testnrelevels]} { namespace delete testnre } +test tailcall-14.1 {in a deleted namespace} -body { + namespace eval ns { + proc p args { + tailcall [namespace current] $args + } + namespace delete [namespace current] + p + } +} -returnCodes 1 -result {namespace "::ns" not found} + +test tailcall-14.1-bc {{in a deleted namespace} {byte compiled}} -body { + namespace eval ns { + proc p args { + tailcall [namespace current] {*}$args + } + namespace delete [namespace current] + p + } +} -returnCodes 1 -result {namespace "::ns" not found} + # cleanup ::tcltest::cleanupTests -- cgit v0.12 From 0839047d8bed631eeb82c7c3e26b0f13461717e6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 25 Jun 2018 07:22:19 +0000 Subject: Simplify ToUtf(), expecially for TCL_UTF_MAX>3 (with correct surrogate handling). Fix various typo's --- tests/iogt.test | 2 +- unix/tclUnixSock.c | 6 +++--- unix/tclUnixThrd.c | 6 +++--- win/tclWinInit.c | 19 +++++++++++-------- win/tclWinSock.c | 16 ++++++++-------- win/tclWinThrd.c | 8 ++++---- 6 files changed, 30 insertions(+), 27 deletions(-) diff --git a/tests/iogt.test b/tests/iogt.test index 1ed89f7..269a0ba 100644 --- a/tests/iogt.test +++ b/tests/iogt.test @@ -608,7 +608,7 @@ test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} -setup { variable copy 1 } } -constraints {testchannel knownBug} -body { - # This test to check the validity of aquired Tcl_Channel references is not + # This test to check the validity of acquired Tcl_Channel references is not # possible because even a backgrounded fcopy will immediately start to # copy data, without waiting for the event loop. This is done only in case # of an underflow on the read size!. So stacking transforms after the diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index e418ff0..90c72c0 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -1099,7 +1099,7 @@ TcpGetHandleProc( * TcpAsyncCallback -- * * Called by the event handler that TcpConnect sets up internally for - * [socket -async] to get notified when the asyncronous connection + * [socket -async] to get notified when the asynchronous connection * attempt has succeeded or failed. * * ---------------------------------------------------------------------- @@ -1132,7 +1132,7 @@ TcpAsyncCallback( * * Remarks: * A single host name may resolve to more than one IP address, e.g. for - * an IPv4/IPv6 dual stack host. For handling asyncronously connecting + * an IPv4/IPv6 dual stack host. For handling asynchronously connecting * sockets in the background for such hosts, this function can act as a * coroutine. On the first call, it sets up the control variables for the * two nested loops over the local and remote addresses. Once the first @@ -1140,7 +1140,7 @@ TcpAsyncCallback( * event handler for that socket, and returns. When the callback occurs, * control is transferred to the "reenter" label, right after the initial * return and the loops resume as if they had never been interrupted. - * For syncronously connecting sockets, the loops work the usual way. + * For synchronously connecting sockets, the loops work the usual way. * * ---------------------------------------------------------------------- */ diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index 0476d85..0609230 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -316,7 +316,7 @@ TclpInitUnlock(void) * in finalization; it is hidden during creation of the objects. * * This lock must be different than the initLock because the initLock is - * held during creation of syncronization objects. + * held during creation of synchronization objects. * * Results: * None. @@ -407,7 +407,7 @@ Tcl_GetAllocMutex(void) * None. * * Side effects: - * May block the current thread. The mutex is aquired when this returns. + * May block the current thread. The mutex is acquired when this returns. * Will allocate memory for a pthread_mutex_t and initialize this the * first time this Tcl_Mutex is used. * @@ -511,7 +511,7 @@ TclpFinalizeMutex( * None. * * Side effects: - * May block the current thread. The mutex is aquired when this returns. + * May block the current thread. The mutex is acquired when this returns. * Will allocate memory for a pthread_mutex_t and initialize this the * first time this Tcl_Mutex is used. * diff --git a/win/tclWinInit.c b/win/tclWinInit.c index 8e567e3..ff5327d 100644 --- a/win/tclWinInit.c +++ b/win/tclWinInit.c @@ -112,7 +112,12 @@ static ProcessGlobalValue sourceLibraryDir = {0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL}; static void AppendEnvironment(Tcl_Obj *listPtr, const char *lib); -static int ToUtf(const WCHAR *wSrc, char *dst); + +#if TCL_UTF_MAX < 4 +static void ToUtf(const WCHAR *wSrc, char *dst); +#else +#define ToUtf(wSrc, dst) WideCharToMultiByte(CP_UTF8, 0, wSrc, -1, dst, MAX_PATH * TCL_UTF_MAX, NULL, NULL) +#endif /* *--------------------------------------------------------------------------- @@ -435,7 +440,7 @@ InitializeSourceLibraryDir( * * ToUtf -- * - * Convert a char string to a UTF string. + * Convert a wchar string to a UTF string. * * Results: * None. @@ -446,21 +451,19 @@ InitializeSourceLibraryDir( *--------------------------------------------------------------------------- */ -static int +#if TCL_UTF_MAX < 4 +static void ToUtf( const WCHAR *wSrc, char *dst) { - char *start; - - start = dst; while (*wSrc != '\0') { dst += Tcl_UniCharToUtf(*wSrc, dst); wSrc++; } *dst = '\0'; - return (int) (dst - start); } +#endif /* *--------------------------------------------------------------------------- @@ -660,7 +663,7 @@ TclpSetVariables( * TclpFindVariable -- * * Locate the entry in environ for a given name. On Unix this routine is - * case sensitive, on Windows this matches mioxed case. + * case sensitive, on Windows this matches mixed case. * * Results: * The return value is the index in environ of an entry with the name diff --git a/win/tclWinSock.c b/win/tclWinSock.c index da2e60a..e2479e81 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -686,7 +686,7 @@ WaitForConnect( } /* - * A non blocking socket waiting for an asyncronous connect + * A non blocking socket waiting for an asynchronous connect * returns directly the error EWOULDBLOCK */ @@ -1606,9 +1606,9 @@ TcpGetHandleProc( * * This might be called in 3 circumstances: * - By a regular socket command - * - By the event handler to continue an asynchroneous connect + * - By the event handler to continue an asynchronously connect * - By a blocking socket function (gets/puts) to terminate the - * connect synchroneously + * connect synchronously * * Results: * TCL_OK, if the socket was successfully connected or an asynchronous @@ -1620,7 +1620,7 @@ TcpGetHandleProc( * * Remarks: * A single host name may resolve to more than one IP address, e.g. for - * an IPv4/IPv6 dual stack host. For handling asyncronously connecting + * an IPv4/IPv6 dual stack host. For handling asynchronously connecting * sockets in the background for such hosts, this function can act as a * coroutine. On the first call, it sets up the control variables for the * two nested loops over the local and remote addresses. Once the first @@ -1628,7 +1628,7 @@ TcpGetHandleProc( * event handler for that socket, and returns. When the callback occurs, * control is transferred to the "reenter" label, right after the initial * return and the loops resume as if they had never been interrupted. - * For syncronously connecting sockets, the loops work the usual way. + * For synchronously connecting sockets, the loops work the usual way. * *---------------------------------------------------------------------- */ @@ -1718,7 +1718,7 @@ TcpConnect( continue; } /* - * For asyncroneous connect set the socket in nonblocking mode + * For asynchroneous connect set the socket in nonblocking mode * and activate connect notification */ if (async_connect) { @@ -1806,7 +1806,7 @@ TcpConnect( /* * Clear the tsd socket list pointer if we did not wait for - * the FD_CONNECT asyncroneously + * the FD_CONNECT asynchroneously */ tsdPtr->pendingTcpState = NULL; @@ -1868,7 +1868,7 @@ out: SetEvent(tsdPtr->socketListLock); } /* - * Error message on syncroneous connect + * Error message on synchroneous connect */ if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c index 8f3ddb9..0f83526 100644 --- a/win/tclWinThrd.c +++ b/win/tclWinThrd.c @@ -247,7 +247,7 @@ TclpThreadCreate( /* * The only purpose of this is to decrement the reference count so the - * OS resources will be reaquired when the thread closes. + * OS resources will be reacquired when the thread closes. */ CloseHandle(tHandle); @@ -405,7 +405,7 @@ TclpInitUnlock(void) * mutexes, condition variables, and thread local storage keys. * * This lock must be different than the initLock because the initLock is - * held during creation of syncronization objects. + * held during creation of synchronization objects. * * Results: * None. @@ -555,7 +555,7 @@ static void FinalizeConditionEvent(ClientData data); * None. * * Side effects: - * May block the current thread. The mutex is aquired when this returns. + * May block the current thread. The mutex is acquired when this returns. * *---------------------------------------------------------------------- */ @@ -655,7 +655,7 @@ TclpFinalizeMutex( * None. * * Side effects: - * May block the current thread. The mutex is aquired when this returns. + * May block the current thread. The mutex is acquired when this returns. * Will allocate memory for a HANDLE and initialize this the first time * this Tcl_Condition is used. * -- cgit v0.12