diff options
| author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2018-12-13 20:01:34 (GMT) |
|---|---|---|
| committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2018-12-13 20:01:34 (GMT) |
| commit | 9c5dc4c207e6610aa3d55e2d4d081779848a21c6 (patch) | |
| tree | fc9cd49a7e54859c46ce5c62037c410d47c2211a | |
| parent | 1961633531b70d5a6e627f86153f4d15e722ea8b (diff) | |
| download | tcl-9c5dc4c207e6610aa3d55e2d4d081779848a21c6.zip tcl-9c5dc4c207e6610aa3d55e2d4d081779848a21c6.tar.gz tcl-9c5dc4c207e6610aa3d55e2d4d081779848a21c6.tar.bz2 | |
Fix 2 TIP #502 corner-cases. Those corner-cases where (probably) always wrong on 32-bit systems, but now we have a TIP describing how it's expected to behave!
Thanks to Emiliano for noticing and reporting it. Added 6 test-cases for completeness, 2 of them failed before this fix.
Also optimize TclStringLast() a bit, implementing the pre-condition tests as in TclStringFirst().
| -rw-r--r-- | generic/tclStringObj.c | 32 | ||||
| -rw-r--r-- | tests/string.test | 18 |
2 files changed, 41 insertions, 9 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 4e6cdc5..72ca7cd 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -3568,6 +3568,10 @@ TclStringFirst( /* Find bytes in bytes */ bh = Tcl_GetByteArrayFromObj(haystack, &lh); + if ((lh < ln) || (start > lh - ln)) { + /* Don't start the loop if there cannot be a valid answer */ + return -1; + } end = bh + lh; try = bh + start; @@ -3610,6 +3614,10 @@ TclStringFirst( Tcl_UniChar *un = Tcl_GetUnicodeFromObj(needle, &ln); uh = Tcl_GetUnicodeFromObj(haystack, &lh); + if ((lh < ln) || (start > lh - ln)) { + /* Don't start the loop if there cannot be a valid answer */ + return -1; + } end = uh + lh; for (try = uh + start; try + ln <= end; try++) { @@ -3658,20 +3666,19 @@ TclStringLast( return -1; } - lh = Tcl_GetCharLength(haystack); - if (last >= lh) { - last = lh - 1; - } - - if (last < ln - 1) { - return -1; - } - if (TclIsPureByteArray(needle) && TclIsPureByteArray(haystack)) { unsigned char *try, *bh = Tcl_GetByteArrayFromObj(haystack, &lh); unsigned char *bn = Tcl_GetByteArrayFromObj(needle, &ln); + if (last >= lh) { + last = lh - 1; + } + if (last + 1 < ln) { + /* Don't start the loop if there cannot be a valid answer */ + return -1; + } try = bh + last + 1 - ln; + while (try >= bh) { if ((*try == bn[0]) && (0 == memcmp(try+1, bn+1, ln-1))) { @@ -3686,6 +3693,13 @@ TclStringLast( Tcl_UniChar *try, *uh = Tcl_GetUnicodeFromObj(haystack, &lh); Tcl_UniChar *un = Tcl_GetUnicodeFromObj(needle, &ln); + if (last >= lh) { + last = lh - 1; + } + if (last + 1 < ln) { + /* Don't start the loop if there cannot be a valid answer */ + return -1; + } try = uh + last + 1 - ln; while (try >= uh) { if ((*try == un[0]) diff --git a/tests/string.test b/tests/string.test index 81fe130..c7df26d 100644 --- a/tests/string.test +++ b/tests/string.test @@ -421,6 +421,24 @@ test string-4.16.$noComp {string first, normal string vs pure unicode string} { run {list [representationpoke $s] [representationpoke $m] \ [string first $m $s]} } {{string 1} {string 0} 2} +test string-4.17.$noComp {string first, corner case} { + run {string first a aaa 4294967295} +} {-1} +test string-4.18.$noComp {string first, corner case} { + run {string first a aaa -1} +} {0} +test string-4.19.$noComp {string first, corner case} { + run {string first a aaa end-5} +} {0} +test string-4.20.$noComp {string last, corner case} { + run {string last a aaa 4294967295} +} {2} +test string-4.21.$noComp {string last, corner case} { + run {string last a aaa -1} +} {-1} +test string-4.22.$noComp {string last, corner case} { + run {string last a aaa end-5} +} {-1} test string-5.1.$noComp {string index} { list [catch {run {string index}} msg] $msg |
