From 9d8f556865a0a282039621759755c0cf44664039 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 15 Nov 2012 20:25:01 +0000 Subject: Contributed patch from Andy Goth. --- generic/tclBinary.c | 91 ++++++++++++++++++++++++++++++++++++++--------------- tests/binary.test | 21 +++++++++++++ 2 files changed, 86 insertions(+), 26 deletions(-) diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 3d8b24c..b29f1d8 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -2658,7 +2658,7 @@ BinaryDecode64( Tcl_Obj *const objv[]) { Tcl_Obj *resultObj = NULL; - unsigned char *data, *datastart, *dataend, c; + unsigned char *data, *datastart, *dataend, c = '\0'; unsigned char *begin = NULL; unsigned char *cursor = NULL; int strict = 0; @@ -2691,43 +2691,82 @@ BinaryDecode64( while (data < dataend) { unsigned long value = 0; - for (i=0 ; i<4 ; i++) { + /* + * Decode the current block. Each base64 block consists of four input + * characters A-Z, a-z, 0-9, +, or /. Each character supplies six bits + * of output data, so each block's output is 24 bits (three bytes) in + * length. The final block can be shorter by one or two bytes, denoted + * by the input ending with one or two ='s, respectively. + */ + for (i = 0; i < 4; i++) { + /* + * Get the next input character. At end of input, pad with at most + * two ='s. If more than two ='s would be needed, instead discard + * the block read thus far. + */ if (data < dataend) { c = *data++; + } else if (i > 1) { + c = '='; + } else { + cut += 3; + break; + } - if (c >= 'A' && c <= 'Z') { - value = (value << 6) | ((c - 'A') & 0x3f); - } else if (c >= 'a' && c <= 'z') { - value = (value << 6) | ((c - 'a' + 26) & 0x3f); - } else if (c >= '0' && c <= '9') { - value = (value << 6) | ((c - '0' + 52) & 0x3f); - } else if (c == '+') { - value = (value << 6) | 0x3e; - } else if (c == '/') { - value = (value << 6) | 0x3f; - } else if (c == '=') { - value <<= 6; - if (cut < 2) { - cut++; - } + /* + * Load the character into the block value. Handle ='s specially + * because they're only valid as the last character or two of the + * final block of input. Unless strict mode is enabled, skip any + * input whitespace characters. + */ + if (cut) { + if (c == '=' && i > 1) { + value <<= 6; + cut++; + } else if (!strict && isspace(c)) { + i--; } else { - if (strict || !isspace(c)) { - goto bad64; - } - i--; - continue; + goto bad64; } - } else { + } else if (c >= 'A' && c <= 'Z') { + value = (value << 6) | ((c - 'A') & 0x3f); + } else if (c >= 'a' && c <= 'z') { + value = (value << 6) | ((c - 'a' + 26) & 0x3f); + } else if (c >= '0' && c <= '9') { + value = (value << 6) | ((c - '0' + 52) & 0x3f); + } else if (c == '+') { + value = (value << 6) | 0x3e; + } else if (c == '/') { + value = (value << 6) | 0x3f; + } else if (c == '=') { value <<= 6; cut++; + } else if (strict || !isspace(c)) { + goto bad64; + } else { + i--; } } *cursor++ = UCHAR((value >> 16) & 0xff); *cursor++ = UCHAR((value >> 8) & 0xff); *cursor++ = UCHAR(value & 0xff); - } - if (cut > size) { - cut = size; + + /* + * Since = is only valid within the final block, if it was encountered + * but there are still more input characters, confirm that strict mode + * is off and all subsequent characters are whitespace. + */ + if (cut && data < dataend) { + if (strict) { + goto bad64; + } else { + for (; data < dataend; data++) { + if (!isspace(*data)) { + goto bad64; + } + } + } + } } Tcl_SetByteArrayLength(resultObj, cursor - begin - cut); Tcl_SetObjResult(interp, resultObj); diff --git a/tests/binary.test b/tests/binary.test index 6c00508..ccd0f29 100644 --- a/tests/binary.test +++ b/tests/binary.test @@ -2642,6 +2642,27 @@ test binary-73.23 {binary decode base64} -body { test binary-73.24 {binary decode base64} -body { string length [binary decode base64 " "] } -result 0 +test binary-73.25 {binary decode base64} -body { + list [string length [set r [binary decode base64 WA==\n]]] $r +} -result {1 X} +test binary-73.26 {binary decode base64} -body { + list [string length [set r [binary decode base64 WFk=\n]]] $r +} -result {2 XY} +test binary-73.27 {binary decode base64} -body { + list [string length [set r [binary decode base64 WFla\n]]] $r +} -result {3 XYZ} +test binary-73.28 {binary decode base64} -body { + list [string length [set r [binary decode base64 -strict WA==\n]]] $r +} -returnCodes error -match glob -result {invalid base64 character *} +test binary-73.29 {binary decode base64} -body { + list [string length [set r [binary decode base64 -strict WFk=\n]]] $r +} -returnCodes error -match glob -result {invalid base64 character *} +test binary-73.30 {binary decode base64} -body { + list [string length [set r [binary decode base64 -strict WFla\n]]] $r +} -returnCodes error -match glob -result {invalid base64 character *} +test binary-73.31 {binary decode base64} -body { + list [string length [set r [binary decode base64 WA==WFla]]] $r +} -returnCodes error -match glob -result {invalid base64 character *} test binary-74.1 {binary encode uuencode} -body { binary encode uuencode -- cgit v0.12 From 094f23c172acca8f32b0888cd536f01fc1daab1b Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 19 Nov 2012 22:08:35 +0000 Subject: [Bug 3588366]: Corrected implementation of bounds restriction for end-indexed compiled [string range]. Thanks to Emiliano Gavilan for diagnosis and fix. --- ChangeLog | 6 ++++++ generic/tclExecute.c | 3 --- tests/lrange.test | 14 +++++++++++++- tests/stringComp.test | 14 +++++++++++--- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c16eaa..70234e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-11-19 Donal K. Fellows + + * generic/tclExecute.c (INST_STR_RANGE_IMM): [Bug 3588366]: Corrected + implementation of bounds restriction for end-indexed compiled [string + range]. Thanks to Emiliano Gavilan for diagnosis and fix. + 2012-11-15 Jan Nijtmans IMPLEMENTATION OF TIP#416 diff --git a/generic/tclExecute.c b/generic/tclExecute.c index cf8f9e7..2b5f713 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -4962,9 +4962,6 @@ TEBCresume( } if (toIdx < -1) { toIdx += 1 + length; - if (toIdx < 0) { - toIdx = 0; - } } else if (toIdx >= length) { toIdx = length - 1; } diff --git a/tests/lrange.test b/tests/lrange.test index 6c81872..17a757e 100644 --- a/tests/lrange.test +++ b/tests/lrange.test @@ -15,7 +15,7 @@ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } - + test lrange-1.1 {range of list elements} { lrange {a b c d} 1 2 } {b c} @@ -61,9 +61,11 @@ test lrange-1.14 {range of list elements} { test lrange-1.15 {range of list elements} { concat \"[lrange {a b \{\ } 0 2]" } {"a b \{\ "} +# emacs highlighting bug workaround --> " test lrange-1.16 {list element quoting} { lrange {[append a .b]} 0 end } {{[append} a .b\]} + test lrange-2.1 {error conditions} { list [catch {lrange a b} msg] $msg } {1 {wrong # args: should be "lrange list first last"}} @@ -83,6 +85,16 @@ test lrange-2.6 {error conditions} { list [catch {lrange "a b c \{ d e" 1 4} msg] $msg } {1 {unmatched open brace in list}} +test lrange-3.1 {Bug 3588366: end-offsets before start} { + apply {l { + lrange $l 0 end-5 + }} {1 2 3 4 5} +} {} + # cleanup ::tcltest::cleanupTests return + +# Local Variables: +# mode: tcl +# End: diff --git a/tests/stringComp.test b/tests/stringComp.test index 56fb69d..9e00ce7 100644 --- a/tests/stringComp.test +++ b/tests/stringComp.test @@ -26,7 +26,7 @@ catch [list package require -exact Tcltest [info patchlevel]] # Some tests require the testobj command testConstraint testobj [expr {[info commands testobj] != {}}] - + test stringComp-1.1 {error conditions} { proc foo {} {string gorp a b} list [catch {foo} msg] $msg @@ -677,7 +677,11 @@ test stringComp-11.54 {string match, failure} { } {0 1 1 1 0 0} ## string range -## not yet bc +test stringComp-12.1 {Bug 3588366: end-offsets before start} { + apply {s { + string range $s 0 end-5 + }} 12345 +} {} ## string repeat ## not yet bc @@ -699,8 +703,12 @@ test stringComp-11.54 {string match, failure} { ## string word* ## not yet bc - + # cleanup catch {rename foo {}} ::tcltest::cleanupTests return + +# Local Variables: +# mode: tcl +# End: -- cgit v0.12 From 2742530e9d84e0347a415ae41cc5057a80a23d35 Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 20 Nov 2012 12:04:51 +0000 Subject: very minor style tweaks --- generic/tclBinary.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/generic/tclBinary.c b/generic/tclBinary.c index b29f1d8..5c33308 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -2663,7 +2663,7 @@ BinaryDecode64( unsigned char *cursor = NULL; int strict = 0; int i, index, size, cut = 0, count = 0; - enum {OPT_STRICT }; + enum { OPT_STRICT }; static const char *const optStrings[] = { "-strict", NULL }; if (objc < 2 || objc > 3) { @@ -2698,12 +2698,14 @@ BinaryDecode64( * length. The final block can be shorter by one or two bytes, denoted * by the input ending with one or two ='s, respectively. */ + for (i = 0; i < 4; i++) { /* * Get the next input character. At end of input, pad with at most * two ='s. If more than two ='s would be needed, instead discard * the block read thus far. */ + if (data < dataend) { c = *data++; } else if (i > 1) { @@ -2719,6 +2721,7 @@ BinaryDecode64( * final block of input. Unless strict mode is enabled, skip any * input whitespace characters. */ + if (cut) { if (c == '=' && i > 1) { value <<= 6; @@ -2756,14 +2759,14 @@ BinaryDecode64( * but there are still more input characters, confirm that strict mode * is off and all subsequent characters are whitespace. */ + if (cut && data < dataend) { if (strict) { goto bad64; - } else { - for (; data < dataend; data++) { - if (!isspace(*data)) { - goto bad64; - } + } + for (; data < dataend; data++) { + if (!isspace(*data)) { + goto bad64; } } } -- cgit v0.12 From 0b73c62416cae2c14de0924d798addd849cb5ac2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 22 Nov 2012 08:45:39 +0000 Subject: Fix bug reported by Brian Griffin:

[http://code.activestate.com/lists/tcl-core/12524/] --- generic/tclIndexObj.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 1076e32..cc50fd3 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -207,10 +207,6 @@ Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, entryPtr = NEXT_ENTRY(entryPtr, offset), i++) { for (p1 = key, p2 = *entryPtr; *p1 == *p2; p1++, p2++) { if (*p1 == '\0') { - if (p1 == key) { - /* empty keys never match */ - continue; - } index = i; goto done; } -- cgit v0.12