summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/clock.n5
-rw-r--r--generic/tclIO.c1
-rw-r--r--generic/tclIORChan.c12
-rw-r--r--tests/chanio.test6
-rw-r--r--tests/cmdAH.test3
-rw-r--r--tests/io.test31
-rw-r--r--tests/ioCmd.test9
-rw-r--r--tests/iogt.test23
-rwxr-xr-xunix/configure4
-rw-r--r--unix/tcl.m44
-rw-r--r--unix/tclUnixFile.c6
-rw-r--r--win/tclWinFile.c63
12 files changed, 139 insertions, 28 deletions
diff --git a/doc/clock.n b/doc/clock.n
index 7c4c3df..a0cc63e 100644
--- a/doc/clock.n
+++ b/doc/clock.n
@@ -626,8 +626,9 @@ On output, produces a locale-dependent time of day representation on a
12-hour clock. On input, accepts whatever \fB%r\fR produces.
.TP
\fB%R\fR
-On output, produces a locale-dependent time of day representation on a
-24-hour clock. On input, accepts whatever \fB%R\fR produces.
+On output, the time in 24-hour notation (%H:%M). For a version
+including the seconds, see \fB%T\fR below. On input, accepts whatever
+\fB%R\fR produces.
.TP
\fB%s\fR
On output, simply formats the \fItimeVal\fR argument as a decimal
diff --git a/generic/tclIO.c b/generic/tclIO.c
index f42d390..7a53373 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -12,7 +12,6 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#undef NDEBUG
#include "tclInt.h"
#include "tclIO.h"
#include <assert.h>
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index 7630473..3107f9e 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -438,8 +438,8 @@ static const char *msg_write_nothing = "{write wrote nothing}";
static const char *msg_seek_beforestart = "{Tried to seek before origin}";
#ifdef TCL_THREADS
static const char *msg_send_originlost = "{Channel thread lost}";
-static const char *msg_send_dstlost = "{Owner lost}";
#endif /* TCL_THREADS */
+static const char *msg_send_dstlost = "{Owner lost}";
static const char *msg_dstlost = "-code 1 -level 0 -errorcode NONE -errorinfo {} -errorline 1 {Owner lost}";
/*
@@ -1302,6 +1302,7 @@ ReflectOutput(
/* ASSERT: rcPtr->mode & TCL_WRITABLE */
Tcl_Preserve(rcPtr);
+ Tcl_Preserve(rcPtr->interp);
bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite);
Tcl_IncrRefCount(bufObj);
@@ -1318,6 +1319,14 @@ ReflectOutput(
goto invalid;
}
+ if (Tcl_InterpDeleted(rcPtr->interp)) {
+ /*
+ * The interp was destroyed during InvokeTclMethod().
+ */
+
+ SetChannelErrorStr(rcPtr->chan, msg_send_dstlost);
+ goto invalid;
+ }
if (Tcl_GetIntFromObj(rcPtr->interp, resObj, &written) != TCL_OK) {
Tcl_SetChannelError(rcPtr->chan, MarshallError(rcPtr->interp));
goto invalid;
@@ -1347,6 +1356,7 @@ ReflectOutput(
stop:
Tcl_DecrRefCount(bufObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr->interp);
Tcl_Release(rcPtr);
return written;
invalid:
diff --git a/tests/chanio.test b/tests/chanio.test
index b195f7b..2f2540e 100644
--- a/tests/chanio.test
+++ b/tests/chanio.test
@@ -41,7 +41,7 @@ namespace eval ::tcl::test::io {
# You need a *very* special environment to do some tests. In
# particular, many file systems do not support large-files...
- testConstraint largefileSupport 0
+ testConstraint largefileSupport [expr {$::tcl_platform(os) ne "Darwin"}]
# some tests can only be run is umask is 2
# if "umask" cannot be run, the tests will be skipped.
@@ -4427,10 +4427,10 @@ test chan-io-34.21 {Tcl_Seek and Tcl_Tell on large files} {largefileSupport} {
chan puts -nonewline $f abcdef
lappend l [chan tell $f]
chan close $f
- lappend l [file size $f]
+ lappend l [file size $path(test3)]
# truncate...
chan close [open $path(test3) w]
- lappend l [file size $f]
+ lappend l [file size $path(test3)]
set l
} {0 6 6 4294967296 4294967302 4294967302 0}
diff --git a/tests/cmdAH.test b/tests/cmdAH.test
index dc61ac6..4ca90c6 100644
--- a/tests/cmdAH.test
+++ b/tests/cmdAH.test
@@ -104,6 +104,9 @@ test cmdAH-2.6.1 {Tcl_CdObjCmd} {
list [catch {cd ""} msg] $msg
} {1 {couldn't change working directory to "": no such file or directory}}
+test cmdAH-2.6.3 {Tcl_CdObjCmd, bug #3118489} -returnCodes error -body {
+ cd .\0
+} -result "couldn't change working directory to \".\0\": no such file or directory"
test cmdAH-2.7 {Tcl_ConcatObjCmd} {
concat
} {}
diff --git a/tests/io.test b/tests/io.test
index ff5554e..5f31d8e 100644
--- a/tests/io.test
+++ b/tests/io.test
@@ -41,7 +41,7 @@ testConstraint testthread [llength [info commands testthread]]
# You need a *very* special environment to do some tests. In
# particular, many file systems do not support large-files...
-testConstraint largefileSupport 0
+testConstraint largefileSupport [expr {$::tcl_platform(os) ne "Darwin"}]
# some tests can only be run is umask is 2
# if "umask" cannot be run, the tests will be skipped.
@@ -4019,6 +4019,26 @@ test io-32.11.1 {Tcl_Read from a pipe} {stdio openpipe} {
} {{hello
} {hello
}}
+test io-32.11.1 {Tcl_Read from a pipe} {stdio openpipe} {
+ file delete $path(pipe)
+ set f1 [open $path(pipe) w]
+ puts $f1 {chan configure stdout -translation crlf}
+ puts $f1 {puts [gets stdin]}
+ puts $f1 {puts [gets stdin]}
+ close $f1
+ set f1 [open "|[list [interpreter] $path(pipe)]" r+]
+ puts $f1 hello
+ flush $f1
+ set x ""
+ lappend x [read $f1 6]
+ puts $f1 hello
+ flush $f1
+ lappend x [read $f1]
+ close $f1
+ set x
+} {{hello
+} {hello
+}}
test io-32.12 {Tcl_Read, -nonewline} {
file delete $path(test1)
set f1 [open $path(test1) w]
@@ -4492,10 +4512,10 @@ test io-34.21 {Tcl_Seek and Tcl_Tell on large files} {largefileSupport} {
puts -nonewline $f abcdef
lappend l [tell $f]
close $f
- lappend l [file size $f]
+ lappend l [file size $path(test3)]
# truncate...
close [open $path(test3) w]
- lappend l [file size $f]
+ lappend l [file size $path(test3)]
set l
} {0 6 6 4294967296 4294967302 4294967302 0}
@@ -4788,7 +4808,7 @@ test io-35.18a {Tcl_Eof, eof char, cr write, crlf read} -body {
close $f
list $s $l $e [scan [string index $in end] %c]
} -result {9 8 1 13}
-test io-35.18b {Tcl_Eof, eof char, cr write, crlf read} -constraints knownBug -body {
+test io-35.18b {Tcl_Eof, eof char, cr write, crlf read} -body {
file delete $path(test1)
set f [open $path(test1) w]
fconfigure $f -translation cr -eofchar \x1a
@@ -6884,6 +6904,7 @@ test io-52.12 {coverage of -translation auto} {
set in [open $path(test1)]
chan configure $in -buffersize 8
set out [open $path(test2) w]
+ chan configure $out -translation lf
fcopy $in $out
close $in
close $out
@@ -6898,6 +6919,7 @@ test io-52.13 {coverage of -translation cr} {
set in [open $path(test1)]
chan configure $in -buffersize 8 -translation cr
set out [open $path(test2) w]
+ chan configure $out -translation lf
fcopy $in $out
close $in
close $out
@@ -6912,6 +6934,7 @@ test io-52.14 {coverage of -translation crlf} {
set in [open $path(test1)]
chan configure $in -buffersize 8 -translation crlf
set out [open $path(test2) w]
+ chan configure $out -translation lf
fcopy $in $out
close $in
close $out
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index bb133f9..5a76d48 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -2038,13 +2038,13 @@ test iocmd-32.1 {origin interpreter of moved channel destroyed during access} -m
proc foo {args} {
oninit; onfinal; track;
# destroy interpreter during channel access
- # Actually not possible for an interp to destroy itself.
- interp delete {}
- return}
+ suicide
+ }
set chan [chan create {r w} foo]
fconfigure $chan -buffering none
set chan
}]
+ interp alias $ida suicide {} interp delete $ida
# Move channel to 2nd thread.
interp eval $ida [list testchannel cut $chan]
@@ -2063,8 +2063,7 @@ test iocmd-32.1 {origin interpreter of moved channel destroyed during access} -m
set res
}]
set res
-} -constraints {testchannel impossible} \
- -result {Owner lost}
+} -constraints {testchannel} -result {Owner lost}
test iocmd-32.2 {delete interp of reflected chan} {
# Bug 3034840
diff --git a/tests/iogt.test b/tests/iogt.test
index d4291b3..0e2eb3c 100644
--- a/tests/iogt.test
+++ b/tests/iogt.test
@@ -159,8 +159,8 @@ proc fevent {fdelay idelay blocks script data} {
#puts stdout ">>>>>" ; flush stdout
- uplevel #0 set sock $sk
- set res [uplevel #0 $script]
+ uplevel 1 set sock $sk
+ set res [uplevel 1 $script]
catch {close $sk}
return $res
@@ -686,7 +686,7 @@ test iogt-2.5 {basic I/O, mixed trail} {testchannel} {
} {}
test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} \
- {testchannel unknownFailure} {
+ {testchannel knownBug} {
# This test to check the validity of aquired 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
@@ -703,6 +703,7 @@ test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} \
set fin [open $path(dummy) r]
fevent 1000 500 {20 20 20 10 1 1} {
+ variable copy
close $fin
set fout [open dummyout w]
@@ -740,7 +741,7 @@ test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} \
} {1 {create/write create/read write flush/write flush/read delete/write delete/read}}
-test iogt-4.0 {fileevent readable, after transform} {testchannel unknownFailure} {
+test iogt-4.0 {fileevent readable, after transform} {testchannel knownBug} {
set fin [open $path(dummy) r]
set data [read $fin]
close $fin
@@ -770,10 +771,11 @@ test iogt-4.0 {fileevent readable, after transform} {testchannel unknownFailure}
}
fevent 1000 500 {20 20 20 10 1} {
+ variable stop
audit_flow trail -attach $sock
rblocks_t rbuf trail 23 -attach $sock
- fileevent $sock readable [list Get $sock]
+ fileevent $sock readable [namespace code [list Get $sock]]
flush $sock ; # now, or fcopy will error us out
# But the 1 second delay should be enough to
@@ -871,7 +873,7 @@ delete/write {} *ignored*
delete/read {} *ignored*} ; # catch unescaped quote "
-test iogt-5.0 {EOF simulation} {testchannel unknownFailure} {
+test iogt-5.0 {EOF simulation} {testchannel knownBug} {
set fin [open $path(dummy) r]
set fout [open $path(dummyout) w]
@@ -968,6 +970,15 @@ test iogt-6.0 {Push back} testchannel {
} {xxx}
test iogt-6.1 {Push back and up} {testchannel knownBug} {
+
+ # This test demonstrates the bug/misfeature in the stacked
+ # channel implementation that data can be discarded if it is
+ # read into the buffers of one channel in the stack, and then
+ # that channel is popped before anything above it reads.
+ #
+ # This bug can be worked around by always setting -buffersize
+ # to 1, but who wants to do that?
+
set f [open $path(dummy) r]
# contents of dummy = "abcdefghi..."
diff --git a/unix/configure b/unix/configure
index 02a3725..d268647 100755
--- a/unix/configure
+++ b/unix/configure
@@ -7010,9 +7010,9 @@ echo "$as_me: error: CYGWIN compile is only supported with --enable-threads" >&2
fi
do64bit_ok=yes
if test "x${SHARED_BUILD}" = "x1"; then
- echo "running cd ../win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
+ echo "running cd ${TCL_SRC_DIR}/win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
# The eval makes quoting arguments work.
- if cd ../win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix
+ if cd ${TCL_SRC_DIR}/win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix
then :
else
{ echo "configure: error: configure failed for ../win" 1>&2; exit 1; }
diff --git a/unix/tcl.m4 b/unix/tcl.m4
index 10408a8..b6c86b6 100644
--- a/unix/tcl.m4
+++ b/unix/tcl.m4
@@ -1266,9 +1266,9 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
fi
do64bit_ok=yes
if test "x${SHARED_BUILD}" = "x1"; then
- echo "running cd ../win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
+ echo "running cd ${TCL_SRC_DIR}/win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
# The eval makes quoting arguments work.
- if cd ../win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix
+ if cd ${TCL_SRC_DIR}/win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix
then :
else
{ echo "configure: error: configure failed for ../win" 1>&2; exit 1; }
diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c
index 29f1aba..c5f75a7 100644
--- a/unix/tclUnixFile.c
+++ b/unix/tclUnixFile.c
@@ -1111,6 +1111,12 @@ TclNativeCreateNativeRep(
str = Tcl_GetStringFromObj(validPathPtr, &len);
Tcl_UtfToExternalDString(NULL, str, len, &ds);
len = Tcl_DStringLength(&ds) + sizeof(char);
+ if (strlen(Tcl_DStringValue(&ds)) < len - sizeof(char)) {
+ /* See bug [3118489]: NUL in filenames */
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ }
Tcl_DecrRefCount(validPathPtr);
nativePathPtr = ckalloc((unsigned) len);
memcpy((void*)nativePathPtr, (void*)Tcl_DStringValue(&ds), (size_t) len);
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index ed0c40f..9bf63b1 100644
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1856,6 +1856,9 @@ TclpObjChdir(
nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
+ if (!nativePath) {
+ return -1;
+ }
result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
@@ -3200,13 +3203,69 @@ TclNativeCreateNativeRep(
Tcl_WinUtfToTChar(str, len, &ds);
if (tclWinProcs->useWide) {
WCHAR *wp = (WCHAR *) Tcl_DStringValue(&ds);
- for (; *wp; ++wp) {
- if (*wp=='/') {
+ len = Tcl_DStringLength(&ds)>>1;
+ /*
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ wp[0] = wp[1] = wp[3] = '\\';
+ str += 4;
+ wp += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ wp += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*wp=='/') {
*wp = '\\';
}
+ ++wp;
}
len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
} else {
+ char *p = Tcl_DStringValue(&ds);
+ len = Tcl_DStringLength(&ds);
+ /*
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ p[0] = p[1] = p[3] = '\\';
+ str += 4;
+ p += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ p += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*p < ' ') || strchr("\"*:<>?|", *p)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*p=='/') {
+ *p = '\\';
+ }
+ ++p;
+ }
len = Tcl_DStringLength(&ds) + sizeof(char);
}
Tcl_DecrRefCount(validPathPtr);