diff options
| author | dgp <dgp@users.sourceforge.net> | 2014-05-16 15:05:08 (GMT) | 
|---|---|---|
| committer | dgp <dgp@users.sourceforge.net> | 2014-05-16 15:05:08 (GMT) | 
| commit | 539adc9f7fd227cd270169d162e38e2c991be228 (patch) | |
| tree | 77cdd0683d48082b253c28221385704f4d569ea8 | |
| parent | 3bb92ad0055b8f3e56c9d5d988f5cacc622f8775 (diff) | |
| parent | 5e1812e37c3cfaba1d9285949faf542fb4689594 (diff) | |
| download | tcl-539adc9f7fd227cd270169d162e38e2c991be228.zip tcl-539adc9f7fd227cd270169d162e38e2c991be228.tar.gz tcl-539adc9f7fd227cd270169d162e38e2c991be228.tar.bz2  | |
merge 8.5
| -rw-r--r-- | generic/tclIO.c | 46 | ||||
| -rw-r--r-- | tests/cmdAH.test | 3 | ||||
| -rw-r--r-- | tests/io.test | 79 | ||||
| -rw-r--r-- | unix/tclUnixFile.c | 6 | ||||
| -rw-r--r-- | win/tclWinFile.c | 63 | 
5 files changed, 186 insertions, 11 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 3416b64..a5c77e8 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -5503,7 +5503,6 @@ ReadChars(  	     *	  record \r or \n yet.  	     */ -	    assert(dstRead + 1 == dstDecoded);  	    assert(dst[dstRead] == '\r');  	    assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF); @@ -5524,7 +5523,6 @@ ReadChars(  	    assert(dstWrote == 0);  	    assert(dstRead == 0); -	    assert(dstDecoded == 1);  	    /*  	     * We decoded only the bare cr, and we cannot read a @@ -5579,6 +5577,13 @@ ReadChars(  		return 1;  	    } +	    /* +	     * Revise the dstRead value so that the numChars calc +	     * below correctly computes zero characters read. +	     */ + +	    dstRead = numChars; +  	    /* FALL THROUGH - get more data (dstWrote == 0) */  	} @@ -5605,16 +5610,38 @@ ReadChars(  	}  	if (dstWrote == 0) { +	    ChannelBuffer *nextPtr; -	    /* -	     * We were not able to read any chars.  Maybe there were -	     * not enough src bytes to decode into a char.  Maybe -	     * a lone \r could not be translated (crlf mode).  Need -	     * to combine any unused src bytes we have in the first -	     * buffer with subsequent bytes to try again. +	    /* We were not able to read any chars. */ + +	    assert (numChars == 0); + +	    /*  +	     * There is one situation where this is the correct final +	     * result.  If the src buffer contains only a single \n +	     * byte, and we are in TCL_TRANSLATE_AUTO mode, and +	     * when the translation pass was made the INPUT_SAW_CR +	     * flag was set on the channel.  In that case, the +	     * correct behavior is to consume that \n and produce the +	     * empty string. +	     */ + +	    if (dst[0] == '\n') { +		assert(statePtr->inputTranslation == TCL_TRANSLATE_AUTO); +		assert(dstRead == 1); + +		goto consume; +	    } + +	    /* Otherwise, reading zero characters indicates there's +	     * something incomplete at the end of the src buffer. +	     * Maybe there were not enough src bytes to decode into +	     * a char.  Maybe a lone \r could not be translated (crlf +	     * mode).  Need to combine any unused src bytes we have +	     * in the first buffer with subsequent bytes to try again.  	     */ -	    ChannelBuffer *nextPtr = bufPtr->nextPtr; +	    nextPtr = bufPtr->nextPtr;  	    if (nextPtr == NULL) {  		if (srcLen > 0) { @@ -5651,6 +5678,7 @@ ReadChars(  	statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; +    consume:  	bufPtr->nextRemoved += srcRead;  	if (dstWrote > srcRead + 1) {  	    *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; 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 cc3730d..a2e2397 100644 --- a/tests/io.test +++ b/tests/io.test @@ -1559,6 +1559,45 @@ test io-13.8 {TranslateInputEOL: auto mode: \r\n} {      close $f      set x  } "abcd\ndef" +test io-13.8.1 {TranslateInputEOL: auto mode: \r\n} { +    set f [open $path(test1) w] +    fconfigure $f -translation lf +    puts -nonewline $f "abcd\r\ndef" +    close $f +    set f [open $path(test1)] +    fconfigure $f -translation auto +    set x {} +    lappend x [read $f 5] +    lappend x [read $f] +    close $f +    set x +} [list "abcd\n" "def"] +test io-13.8.2 {TranslateInputEOL: auto mode: \r\n} { +    set f [open $path(test1) w] +    fconfigure $f -translation lf +    puts -nonewline $f "abcd\r\ndef" +    close $f +    set f [open $path(test1)] +    fconfigure $f -translation auto -buffersize 6 +    set x {} +    lappend x [read $f 5] +    lappend x [read $f] +    close $f +    set x +} [list "abcd\n" "def"] +test io-13.8.3 {TranslateInputEOL: auto mode: \r\n} { +    set f [open $path(test1) w] +    fconfigure $f -translation lf +    puts -nonewline $f "abcd\r\n\r\ndef" +    close $f +    set f [open $path(test1)] +    fconfigure $f -translation auto -buffersize 7 +    set x {} +    lappend x [read $f 5] +    lappend x [read $f] +    close $f +    set x +} [list "abcd\n" "\ndef"]  test io-13.9 {TranslateInputEOL: auto mode: \r followed by not \n} {      set f [open $path(test1) w]      fconfigure $f -translation lf @@ -3960,6 +3999,46 @@ test io-32.11 {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.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] 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);  | 
