From 3e8ffff6a3663495e9cbc3fe5eb0dd1798904dbe Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 13 Nov 2018 21:10:33 +0000 Subject: [35a8f1c04a] Fix bad lengths when creating string rep of some lists. --- generic/tclListObj.c | 8 +++++--- generic/tclUtil.c | 17 +++++++++++++++++ tests/list.test | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/generic/tclListObj.c b/generic/tclListObj.c index d7f9aeb..a75c3d3 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -2110,7 +2110,7 @@ UpdateStringOfList( # define LOCAL_SIZE 64 char localFlags[LOCAL_SIZE], *flagPtr = NULL; int numElems, i, length, bytesNeeded = 0; - const char *elem; + const char *elem, *start; char *dst; Tcl_Obj **elemPtrs; List *listRepPtr; @@ -2169,7 +2169,7 @@ UpdateStringOfList( * Pass 2: copy into string rep buffer. */ - dst = Tcl_InitStringRep(listPtr, NULL, bytesNeeded); + start = dst = Tcl_InitStringRep(listPtr, NULL, bytesNeeded); TclOOM(dst, bytesNeeded); for (i = 0; i < numElems; i++) { flagPtr[i] |= (i ? TCL_DONT_QUOTE_HASH : 0); @@ -2177,7 +2177,9 @@ UpdateStringOfList( dst += TclConvertElement(elem, length, dst, flagPtr[i]); *dst++ = ' '; } - (void) Tcl_InitStringRep(listPtr, NULL, bytesNeeded); + + /* Set the string length to what was actually written, the safe choice */ + (void) Tcl_InitStringRep(listPtr, NULL, dst - 1 - start); if (flagPtr != localFlags) { Tcl_Free(flagPtr); diff --git a/generic/tclUtil.c b/generic/tclUtil.c index ea2c7a9..812bcad 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -1044,6 +1044,23 @@ TclScanElement( return 2; } +#if COMPAT + /* + * We have an established history in TclConvertElement() when quoting + * because of a leading hash character to force what would be the + * CONVERT_MASK mode into the CONVERT_BRACE mode. That is, we format + * the element #{a"b} like this: + * {#{a"b}} + * and not like this: + * \#{a\"b} + * This is inconsistent with [list x{a"b}], but we will not change that now. + * Set that preference here so that we compute a tight size requirement. + */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + preferBrace = 1; + } +#endif + if ((*p == '{') || (*p == '"')) { /* * Must escape or protect so leading character of value is not diff --git a/tests/list.test b/tests/list.test index dff5d50..2686bd7 100644 --- a/tests/list.test +++ b/tests/list.test @@ -128,6 +128,24 @@ test list-3.1 {SetListFromAny and lrange/concat results} { test list-4.1 {Bug 3173086} { string is list "{[list \\\\\}]}" } 1 +test list-4.2 {Bug 35a8f1c04a, check correct str-rep} { + set result {} + foreach i { + {#"} {#"""} {#"""""""""""""""} + "#\"{" "#\"\"\"{" "#\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\{" + "#\"}" "#\"\"\"}" "#\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\}" + } { + set list [list $i] + set list [string trim " $list "] + if {[llength $list] > 1 || $i ne [lindex $list 0]} { + lappend result "wrong string-representation of list by '$i', length: [llength $list], list: '$list'" + } + } + set result [join $result \n] +} {} +test list-4.3 {Bug 35a8f1c04a, check correct string length} { + string length [list #""] +} 5 # cleanup ::tcltest::cleanupTests -- cgit v0.12