Tcl Source Code

Check-in [3b0bc7a6e1]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Revise bug fix to support (length == 0) correctly. Added comments and improved safety in caller.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bug-35a8f1c04a
Files: files | file ages | folders
SHA3-256: 3b0bc7a6e179fa1391665d9ee394509201b45c9cef10d5030b46c1f57ef83c33
User & Date: dgp 2018-11-09 15:39:26
Context
2018-11-09
15:47
Additional test Closed-Leaf check-in: 94ad0517c5 user: dgp tags: bug-35a8f1c04a
15:39
Revise bug fix to support (length == 0) correctly. Added comments and improved safety in caller. check-in: 3b0bc7a6e1 user: dgp tags: bug-35a8f1c04a
14:19
closes [35a8f1c04a]: minimalist fix - beware of discrepancy between TclScanElement and TclConvertEle... check-in: 2ec58720e9 user: sebres tags: bug-35a8f1c04a
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclListObj.c.

1868
1869
1870
1871
1872
1873
1874











1875



1876
1877
1878
1879
1880
1881
1882
1883



1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
    }
    bytesNeeded += numElems;

    /*
     * Pass 2: copy into string rep buffer.
     */












    listPtr->length = bytesNeeded - 1;



    listPtr->bytes = ckalloc((unsigned) bytesNeeded);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {
	flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
	elem = TclGetStringFromObj(elemPtrs[i], &length);
	dst += TclConvertElement(elem, length, dst, flagPtr[i]);
	*dst++ = ' ';
    }



    listPtr->bytes[listPtr->length] = '\0';

    if (flagPtr != localFlags) {
	ckfree((char *) flagPtr);
    }
}
 
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */






>
>
>
>
>
>
>
>
>
>
>

>
>
>








>
>
>
|













1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
    }
    bytesNeeded += numElems;

    /*
     * Pass 2: copy into string rep buffer.
     */

    /*
     * We used to set the string length here, relying on a presumed
     * guarantee that the number of bytes TclScanElement() calls reported
     * to be needed was a precise count and not an over-estimate, so long
     * as the same flag values were passed to TclConvertElement().
     *
     * Then we saw [35a8f1c04a], where a bug in TclScanElement() caused
     * that guarantee to fail. Rather than trust there are no more bugs,
     * we set the length after the loop based on what was actually written,
     * an not on what was predicted.
     *
    listPtr->length = bytesNeeded - 1;
     *
     */

    listPtr->bytes = ckalloc((unsigned) bytesNeeded);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {
	flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
	elem = TclGetStringFromObj(elemPtrs[i], &length);
	dst += TclConvertElement(elem, length, dst, flagPtr[i]);
	*dst++ = ' ';
    }
    dst[-1] = '\0';

    /* Here is the safe setting of the string length. */
    listPtr->length = dst - 1 - listPtr->bytes;

    if (flagPtr != localFlags) {
	ckfree((char *) flagPtr);
    }
}
 
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclUtil.c.

940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957

















958
959
960
961
962
963
964
				 * sequences in formatting. */
    int bytesNeeded;		/* Buffer length computed to complete the
				 * element formatting in the selected mode. */
#if COMPAT
    int preferEscape = 0;	/* Use preferences to track whether to use */
    int preferBrace = 0;	/* CONVERT_MASK mode. */
    int braceCount = 0;		/* Count of all braces '{' '}' seen. */

    if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) {
	preferBrace = 1;
    }
#endif

    if ((p == NULL) || (length == 0) || ((*p == '\0') && (length == -1))) {
	/* Empty string element must be brace quoted. */
	*flagPtr = CONVERT_BRACE;
	return 2;
    }


















    if ((*p == '{') || (*p == '"')) {
	/*
	 * Must escape or protect so leading character of value is not
	 * misinterpreted as list element delimiting syntax.
	 */
	forbidNone = 1;






<
<
<
<







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







940
941
942
943
944
945
946




947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
				 * sequences in formatting. */
    int bytesNeeded;		/* Buffer length computed to complete the
				 * element formatting in the selected mode. */
#if COMPAT
    int preferEscape = 0;	/* Use preferences to track whether to use */
    int preferBrace = 0;	/* CONVERT_MASK mode. */
    int braceCount = 0;		/* Count of all braces '{' '}' seen. */




#endif

    if ((p == NULL) || (length == 0) || ((*p == '\0') && (length == -1))) {
	/* Empty string element must be brace quoted. */
	*flagPtr = CONVERT_BRACE;
	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
	 * misinterpreted as list element delimiting syntax.
	 */
	forbidNone = 1;