From 04bb9b292c26675655414e30f8257deca1bbe097 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 22 Apr 2020 16:00:36 +0000 Subject: Attempt to fix [1004065] for TCL_UTF_MAX=4. Disallow building Tcl with TCL_UTF_MAX>4 --- .travis.yml | 13 ------------- generic/tclEncoding.c | 16 ++++++++++------ generic/tclInt.h | 4 ++++ tests/chanio.test | 3 +-- tests/encoding.test | 5 +---- tests/io.test | 4 +--- tests/source.test | 2 +- 7 files changed, 18 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63c1645..b3ac5f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,19 +26,6 @@ matrix: env: - BUILD_DIR=unix - CFGOPT=CFLAGS=-DTCL_UTF_MAX=4 - script: - - make all tcltest - - make test TESTFLAGS="-file utf.test" - - name: "Linux/GCC/Shared: UTF_MAX=6" - os: linux - dist: bionic - compiler: gcc - env: - - BUILD_DIR=unix - - CFGOPT=CFLAGS=-DTCL_UTF_MAX=6 - script: - - make all tcltest - - make test TESTFLAGS="-file utf.test" - name: "Linux/GCC/Static" os: linux dist: bionic diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index 6c16827..d948189 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -2359,13 +2359,12 @@ UnicodeToUtfProc( const char *srcStart, *srcEnd; char *dstEnd, *dstStart; int result, numChars; - Tcl_UniChar ch; + unsigned short ch; result = TCL_OK; - if ((srcLen % sizeof(Tcl_UniChar)) != 0) { + if ((srcLen & 1) != 0) { result = TCL_CONVERT_MULTIBYTE; - srcLen /= sizeof(Tcl_UniChar); - srcLen *= sizeof(Tcl_UniChar); + srcLen--; } srcStart = src; @@ -2383,13 +2382,13 @@ UnicodeToUtfProc( * Special case for 1-byte utf chars for speed. Make sure we * work with Tcl_UniChar-size data. */ - ch = *(Tcl_UniChar *)src; + ch = *(unsigned short *)src; if (ch && ch < 0x80) { *dst++ = (ch & 0xFF); } else { dst += Tcl_UniCharToUtf(ch, dst); } - src += sizeof(Tcl_UniChar); + src += sizeof(unsigned short); } *srcReadPtr = src - srcStart; @@ -2477,6 +2476,11 @@ UtfToUnicodeProc( * by casting dst to a Tcl_UniChar. [Bug 1122671] * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. */ +#if TCL_UTF_MAX > 3 + if (ch & ~0xFFFF) { + ch = 0xFFFD; + } else +#endif #ifdef WORDS_BIGENDIAN *dst++ = (ch >> 8); *dst++ = (ch & 0xFF); diff --git a/generic/tclInt.h b/generic/tclInt.h index 3fa14e7..23a398f 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -102,6 +102,10 @@ typedef int ptrdiff_t; #define NO_WIDE_TYPE #endif +#if (TCL_UTF_MAX != 3) && (TCL_UTF_MAX != 4) +# error "Tcl 8.5 can only be built with TCL_UTF_MAX=3 or TCL_UTF_MAX=4" +#endif + /* * Macros used to cast between pointers and integers (e.g. when storing an int * in ClientData), on 64-bit architectures they avoid gcc warning about "cast diff --git a/tests/chanio.test b/tests/chanio.test index db4544c..5fae431 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -29,7 +29,6 @@ namespace eval ::tcl::test::io { variable msg variable expected - testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 @@ -876,7 +875,7 @@ test chan-io-6.44 {Tcl_GetsObj: input saw cr, not followed by cr} {stdio testcha chan close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] -test chan-io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent ucs2} { +test chan-io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent} { # Tcl_ExternalToUtf() set f [open "|[list [interpreter] $path(cat)]" w+] diff --git a/tests/encoding.test b/tests/encoding.test index af325c1..8722a93 100644 --- a/tests/encoding.test +++ b/tests/encoding.test @@ -32,9 +32,6 @@ proc runtests {} { testConstraint testencoding [llength [info commands testencoding]] testConstraint exec [llength [info commands exec]] -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] - - # TclInitEncodingSubsystem is tested by the rest of this file # TclFinalizeEncodingSubsystem is not currently tested @@ -319,7 +316,7 @@ test encoding-15.3 {UtfToUtfProc null character input} { list [string bytelength $x] [string bytelength $y] $z } {1 2 c080} -test encoding-16.1 {UnicodeToUtfProc} ucs2 { +test encoding-16.1 {UnicodeToUtfProc} { set val [encoding convertfrom unicode NN] list $val [format %x [scan $val %c]] } "\u4e4e 4e4e" diff --git a/tests/io.test b/tests/io.test index 06be982..04fa1d2 100644 --- a/tests/io.test +++ b/tests/io.test @@ -29,8 +29,6 @@ namespace eval ::tcl::test::io { variable msg variable expected -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] - testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 @@ -912,7 +910,7 @@ test io-6.44 {Tcl_GetsObj: input saw cr, not followed by cr} {stdio testchannel close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] -test io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent ucs2} { +test io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent} { # Tcl_ExternalToUtf() set f [open "|[list [interpreter] $path(cat)]" w+] diff --git a/tests/source.test b/tests/source.test index 877921e..1df5ac4 100644 --- a/tests/source.test +++ b/tests/source.test @@ -234,7 +234,7 @@ test source-7.1 {source -encoding test} -setup { } -cleanup { removeFile source.file } -result correct -test source-7.2 {source -encoding test} -constraints ucs2 -setup { +test source-7.2 {source -encoding test} -setup { # This tests for bad interactions between [source -encoding] # and use of the Control-Z character (\u001A) as a cross-platform # EOF character by [source]. Here we write out and the [source] a -- cgit v0.12 From 55d47dd21e8786cc598822fb20b1bf38721eca40 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 22 Apr 2020 16:06:39 +0000 Subject: Oopsee (but not really crucial) --- generic/tclEncoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index d948189..ac9f667 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -2479,7 +2479,7 @@ UtfToUnicodeProc( #if TCL_UTF_MAX > 3 if (ch & ~0xFFFF) { ch = 0xFFFD; - } else + } #endif #ifdef WORDS_BIGENDIAN *dst++ = (ch >> 8); -- cgit v0.12 From 39736552afb862bfd716daf58321449acd40fc63 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 22 Apr 2020 16:12:41 +0000 Subject: Restored a test constraint to tolerate [1004065] (maybe just in time to not need it anymore). --- tests/chanio.test | 5 +++-- tests/encoding.test | 6 +++--- tests/io.test | 5 +++-- tests/source.test | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/chanio.test b/tests/chanio.test index db4544c..ce39997 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -29,7 +29,8 @@ namespace eval ::tcl::test::io { variable msg variable expected - testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] + testConstraint twobyteunit [expr {[llength [info commands testsize]] && + ([testsize unichar] == 2)}] testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 @@ -876,7 +877,7 @@ test chan-io-6.44 {Tcl_GetsObj: input saw cr, not followed by cr} {stdio testcha chan close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] -test chan-io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent ucs2} { +test chan-io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent twobyteunit} { # Tcl_ExternalToUtf() set f [open "|[list [interpreter] $path(cat)]" w+] diff --git a/tests/encoding.test b/tests/encoding.test index af325c1..7313093 100644 --- a/tests/encoding.test +++ b/tests/encoding.test @@ -32,8 +32,8 @@ proc runtests {} { testConstraint testencoding [llength [info commands testencoding]] testConstraint exec [llength [info commands exec]] -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] - +testConstraint twobyteunit [expr {[llength [info commands testsize]] && + ([testsize unichar] == 2)}] # TclInitEncodingSubsystem is tested by the rest of this file # TclFinalizeEncodingSubsystem is not currently tested @@ -319,7 +319,7 @@ test encoding-15.3 {UtfToUtfProc null character input} { list [string bytelength $x] [string bytelength $y] $z } {1 2 c080} -test encoding-16.1 {UnicodeToUtfProc} ucs2 { +test encoding-16.1 {UnicodeToUtfProc} twobyteunit { set val [encoding convertfrom unicode NN] list $val [format %x [scan $val %c]] } "\u4e4e 4e4e" diff --git a/tests/io.test b/tests/io.test index 06be982..82d978e 100644 --- a/tests/io.test +++ b/tests/io.test @@ -29,7 +29,8 @@ namespace eval ::tcl::test::io { variable msg variable expected -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] +testConstraint twobyteunit [expr {[llength [info commands testsize]] && + ([testsize unichar] == 2)}] testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] @@ -912,7 +913,7 @@ test io-6.44 {Tcl_GetsObj: input saw cr, not followed by cr} {stdio testchannel close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] -test io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent ucs2} { +test io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent twobyteunit} { # Tcl_ExternalToUtf() set f [open "|[list [interpreter] $path(cat)]" w+] diff --git a/tests/source.test b/tests/source.test index 877921e..15ff08f 100644 --- a/tests/source.test +++ b/tests/source.test @@ -20,7 +20,8 @@ if {[catch {package require tcltest 2.1}]} { namespace eval ::tcl::test::source { namespace import ::tcltest::* -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] +testConstraint twobyteunit [expr {[llength [info commands testsize]] && + ([testsize unichar] == 2)}] test source-1.1 {source command} -setup { set x "old x value" @@ -234,7 +235,7 @@ test source-7.1 {source -encoding test} -setup { } -cleanup { removeFile source.file } -result correct -test source-7.2 {source -encoding test} -constraints ucs2 -setup { +test source-7.2 {source -encoding test} -constraints twobyteunit -setup { # This tests for bad interactions between [source -encoding] # and use of the Control-Z character (\u001A) as a cross-platform # EOF character by [source]. Here we write out and the [source] a -- cgit v0.12 From 9c0475426c2cec95a034d9393e7d2cf27dd029e2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 22 Apr 2020 16:27:16 +0000 Subject: Another ucs2 testContraint no longer used --- tests/source.test | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/source.test b/tests/source.test index 1df5ac4..dc3c2d8 100644 --- a/tests/source.test +++ b/tests/source.test @@ -20,8 +20,6 @@ if {[catch {package require tcltest 2.1}]} { namespace eval ::tcl::test::source { namespace import ::tcltest::* -testConstraint ucs2 [expr {[format %c 0x010000] eq "\uFFFD"}] - test source-1.1 {source command} -setup { set x "old x value" set y "old y value" -- cgit v0.12 From 9c04c8ce98e2cb1c58d3be6d07bba35b24975443 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 22 Apr 2020 20:49:33 +0000 Subject: Eliminate the -bytestring option of [testutfnext]. No caller needs anything else. --- generic/tclTest.c | 12 ++-- tests/utf.test | 200 +++++++++++++++++++++++++++--------------------------- 2 files changed, 104 insertions(+), 108 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index 7a531b4..65599be 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -7130,15 +7130,11 @@ TestUtfNextCmd( static const char tobetested[] = "\xFF\xFE\xF4\xF2\xF0\xEF\xE8\xE3\xE2\xE1\xE0\xC2\xC1\xC0\x82"; const char *p = tobetested; - if (objc != 3 || strcmp(Tcl_GetString(objv[1]), "-bytestring")) { - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "?-bytestring? bytes"); - return TCL_ERROR; - } - bytes = Tcl_GetStringFromObj(objv[1], &numBytes); - } else { - bytes = (char *) Tcl_GetByteArrayFromObj(objv[2], &numBytes); + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "bytes"); + return TCL_ERROR; } + bytes = (char *) Tcl_GetByteArrayFromObj(objv[1], &numBytes); if (numBytes > sizeof(buffer)-2) { Tcl_AppendResult(interp, "\"testutfnext\" can only handle 30 bytes", NULL); diff --git a/tests/utf.test b/tests/utf.test index fd4e396..beba98c 100644 --- a/tests/utf.test +++ b/tests/utf.test @@ -143,7 +143,7 @@ test utf-5.2 {Tcl_UtfFindLast} {testfindlast testbytestring} { test utf-6.1 {Tcl_UtfNext} testutfnext { # This takes the pointer one past the terminating NUL. # This is really an invalid call. - testutfnext -bytestring {} + testutfnext {} } 1 test utf-6.2 {Tcl_UtfNext} testutfnext { testutfnext A @@ -152,301 +152,301 @@ test utf-6.3 {Tcl_UtfNext} testutfnext { testutfnext AA } 1 test utf-6.4 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring A\xA0 + testutfnext A\xA0 } 1 test utf-6.5 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring A\xD0 + testutfnext A\xD0 } 1 test utf-6.6 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring A\xE8 + testutfnext A\xE8 } 1 test utf-6.7 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring A\xF2 + testutfnext A\xF2 } 1 test utf-6.8 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring A\xF8 + testutfnext A\xF8 } 1 test utf-6.9 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0 + testutfnext \xA0 } 1 test utf-6.10 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0G + testutfnext \xA0G } 1 test utf-6.11 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0\xA0 + testutfnext \xA0\xA0 } 1 test utf-6.12 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0\xD0 + testutfnext \xA0\xD0 } 1 test utf-6.13 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0\xE8 + testutfnext \xA0\xE8 } 1 test utf-6.14 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0\xF2 + testutfnext \xA0\xF2 } 1 test utf-6.15 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xA0\xF8 + testutfnext \xA0\xF8 } 1 test utf-6.16 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0 + testutfnext \xD0 } 1 test utf-6.17 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0G + testutfnext \xD0G } 1 test utf-6.18 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0 + testutfnext \xD0\xA0 } 2 test utf-6.19 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xD0 + testutfnext \xD0\xD0 } 1 test utf-6.20 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xE8 + testutfnext \xD0\xE8 } 1 test utf-6.21 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xF2 + testutfnext \xD0\xF2 } 1 test utf-6.22 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xF8 + testutfnext \xD0\xF8 } 1 test utf-6.23 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8 + testutfnext \xE8 } 1 test utf-6.24 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8G + testutfnext \xE8G } 1 test utf-6.25 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0 + testutfnext \xE8\xA0 } 1 test utf-6.26 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xD0 + testutfnext \xE8\xD0 } 1 test utf-6.27 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xE8 + testutfnext \xE8\xE8 } 1 test utf-6.28 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xF2 + testutfnext \xE8\xF2 } 1 test utf-6.29 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xF8 + testutfnext \xE8\xF8 } 1 test utf-6.30 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2 + testutfnext \xF2 } 1 test utf-6.31 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2G + testutfnext \xF2G } 1 test utf-6.32 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0 + testutfnext \xF2\xA0 } 1 test utf-6.33 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xD0 + testutfnext \xF2\xD0 } 1 test utf-6.34 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xE8 + testutfnext \xF2\xE8 } 1 test utf-6.35 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xF2 + testutfnext \xF2\xF2 } 1 test utf-6.36 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xF8 + testutfnext \xF2\xF8 } 1 test utf-6.37 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8 + testutfnext \xF8 } 1 test utf-6.38 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8G + testutfnext \xF8G } 1 test utf-6.39 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8\xA0 + testutfnext \xF8\xA0 } 1 test utf-6.40 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8\xD0 + testutfnext \xF8\xD0 } 1 test utf-6.41 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8\xE8 + testutfnext \xF8\xE8 } 1 test utf-6.42 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8\xF2 + testutfnext \xF8\xF2 } 1 test utf-6.43 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF8\xF8 + testutfnext \xF8\xF8 } 1 test utf-6.44 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0G + testutfnext \xD0\xA0G } 2 test utf-6.45 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0\xA0 + testutfnext \xD0\xA0\xA0 } 2 test utf-6.46 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0\xD0 + testutfnext \xD0\xA0\xD0 } 2 test utf-6.47 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0\xE8 + testutfnext \xD0\xA0\xE8 } 2 test utf-6.48 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0\xF2 + testutfnext \xD0\xA0\xF2 } 2 test utf-6.49 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xD0\xA0\xF8 + testutfnext \xD0\xA0\xF8 } 2 test utf-6.50 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0G + testutfnext \xE8\xA0G } 1 test utf-6.51 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0 + testutfnext \xE8\xA0\xA0 } 3 test utf-6.52 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xD0 + testutfnext \xE8\xA0\xD0 } 1 test utf-6.53 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xE8 + testutfnext \xE8\xA0\xE8 } 1 test utf-6.54 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xF2 + testutfnext \xE8\xA0\xF2 } 1 test utf-6.55 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xF8 + testutfnext \xE8\xA0\xF8 } 1 test utf-6.56 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0G + testutfnext \xF2\xA0G } 1 test utf-6.57 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0 + testutfnext \xF2\xA0\xA0 } 1 test utf-6.58 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xD0 + testutfnext \xF2\xA0\xD0 } 1 test utf-6.59 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xE8 + testutfnext \xF2\xA0\xE8 } 1 test utf-6.60 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xF2 + testutfnext \xF2\xA0\xF2 } 1 test utf-6.61 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xF8 + testutfnext \xF2\xA0\xF8 } 1 test utf-6.62 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0G + testutfnext \xE8\xA0\xA0G } 3 test utf-6.63 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0\xA0 + testutfnext \xE8\xA0\xA0\xA0 } 3 test utf-6.64 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0\xD0 + testutfnext \xE8\xA0\xA0\xD0 } 3 test utf-6.65 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0\xE8 + testutfnext \xE8\xA0\xA0\xE8 } 3 test utf-6.66 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0\xF2 + testutfnext \xE8\xA0\xA0\xF2 } 3 test utf-6.67 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xE8\xA0\xA0\xF8 + testutfnext \xE8\xA0\xA0\xF8 } 3 test utf-6.68 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0G + testutfnext \xF2\xA0\xA0G } 1 test utf-6.69.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0 + testutfnext \xF2\xA0\xA0\xA0 } 1 test utf-6.69.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0 + testutfnext \xF2\xA0\xA0\xA0 } 4 test utf-6.70 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0\xD0 + testutfnext \xF2\xA0\xA0\xD0 } 1 test utf-6.71 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0\xE8 + testutfnext \xF2\xA0\xA0\xE8 } 1 test utf-6.71 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0\xF2 + testutfnext \xF2\xA0\xA0\xF2 } 1 test utf-6.73 {Tcl_UtfNext} testutfnext { - testutfnext -bytestring \xF2\xA0\xA0\xF8 + testutfnext \xF2\xA0\xA0\xF8 } 1 test utf-6.74.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0G + testutfnext \xF2\xA0\xA0\xA0G } 1 test utf-6.74.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0G + testutfnext \xF2\xA0\xA0\xA0G } 4 test utf-6.75.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xA0 + testutfnext \xF2\xA0\xA0\xA0\xA0 } 1 test utf-6.75.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xA0 + testutfnext \xF2\xA0\xA0\xA0\xA0 } 4 test utf-6.76.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xD0 + testutfnext \xF2\xA0\xA0\xA0\xD0 } 1 test utf-6.76.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xD0 + testutfnext \xF2\xA0\xA0\xA0\xD0 } 4 test utf-6.77.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xE8 + testutfnext \xF2\xA0\xA0\xA0\xE8 } 1 test utf-6.77.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xE8 + testutfnext \xF2\xA0\xA0\xA0\xE8 } 4 test utf-6.78.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xF2 + testutfnext \xF2\xA0\xA0\xA0\xF2 } 1 test utf-6.78.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0\xF2 + testutfnext \xF2\xA0\xA0\xA0\xF2 } 4 test utf-6.79.0 {Tcl_UtfNext} {testutfnext ucs2} { - testutfnext -bytestring \xF2\xA0\xA0\xA0G\xF8 + testutfnext \xF2\xA0\xA0\xA0G\xF8 } 1 test utf-6.79.1 {Tcl_UtfNext} {testutfnext fullutf} { - testutfnext -bytestring \xF2\xA0\xA0\xA0G\xF8 + testutfnext \xF2\xA0\xA0\xA0G\xF8 } 4 test utf-6.80 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xC0\x80 + testutfnext \xC0\x80 } 2 test utf-6.81 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xC0\x81 + testutfnext \xC0\x81 } 1 test utf-6.82 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xC1\x80 + testutfnext \xC1\x80 } 1 test utf-6.83 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xC2\x80 + testutfnext \xC2\x80 } 2 test utf-6.84 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xE0\x80\x80 + testutfnext \xE0\x80\x80 } 1 test utf-6.85 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xE0\xA0\x80 + testutfnext \xE0\xA0\x80 } 3 test utf-6.86 {Tcl_UtfNext - overlong sequences} testutfnext { - testutfnext -bytestring \xF0\x80\x80\x80 + testutfnext \xF0\x80\x80\x80 } 1 test utf-6.87.0 {Tcl_UtfNext - overlong sequences} {testutfnext ucs2} { - testutfnext -bytestring \xF0\x90\x80\x80 + testutfnext \xF0\x90\x80\x80 } 1 test utf-6.87.1 {Tcl_UtfNext - overlong sequences} {testutfnext fullutf} { - testutfnext -bytestring \xF0\x90\x80\x80 + testutfnext \xF0\x90\x80\x80 } 4 test utf-6.88 {Tcl_UtfNext, pointing to 2th byte of 3-byte valid sequence} {testutfnext} { - testutfnext -bytestring \xA0\xA0 + testutfnext \xA0\xA0 } 1 test utf-6.89 {Tcl_UtfNext, pointing to 2th byte of 3-byte invalid sequence} {testutfnext} { - testutfnext -bytestring \x80\x80 + testutfnext \x80\x80 } 1 test utf-6.90.0 {Tcl_UtfNext, validity check [493dccc2de]} {testutfnext ucs2} { - testutfnext -bytestring \xF4\x8F\xBF\xBF + testutfnext \xF4\x8F\xBF\xBF } 1 test utf-6.90.1 {Tcl_UtfNext, validity check [493dccc2de]} {testutfnext fullutf} { - testutfnext -bytestring \xF4\x8F\xBF\xBF + testutfnext \xF4\x8F\xBF\xBF } 4 test utf-6.91 {Tcl_UtfNext, validity check [493dccc2de]} testutfnext { - testutfnext -bytestring \xF4\x90\x80\x80 + testutfnext \xF4\x90\x80\x80 } 1 test utf-6.92 {Tcl_UtfNext, pointing to 2th byte of 4-byte invalid sequence} testutfnext { - testutfnext -bytestring \xA0\xA0\xA0 + testutfnext \xA0\xA0\xA0 } 1 test utf-6.93 {Tcl_UtfNext, pointing to 2th byte of 4-byte invalid sequence} testutfnext { - testutfnext -bytestring \x80\x80\x80 + testutfnext \x80\x80\x80 } 1 test utf-7.1 {Tcl_UtfPrev} testutfprev { -- cgit v0.12 From 7f1a39781fafdf8fc0e10176a7fed4e0713a8866 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 22 Apr 2020 21:28:17 +0000 Subject: Add optional second argument to [testutfnext] that can limit how many bytes are permitted to be read. Needed to test protection of buffer overruns. --- generic/tclTest.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index 65599be..76a827a 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -7123,27 +7123,54 @@ TestUtfNextCmd( int objc, Tcl_Obj *const objv[]) { - int numBytes; + int numBytes; /* Number of bytes supplied in the test string */ + int offset; /* Number of bytes we are permitted to read */ char *bytes; const char *result, *first; char buffer[32]; static const char tobetested[] = "\xFF\xFE\xF4\xF2\xF0\xEF\xE8\xE3\xE2\xE1\xE0\xC2\xC1\xC0\x82"; const char *p = tobetested; - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "bytes"); + if (objc < 2 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "bytes ?numBytes?"); return TCL_ERROR; } + bytes = (char *) Tcl_GetByteArrayFromObj(objv[1], &numBytes); + offset = numBytes + TCL_UTF_MAX; /* If no constraint is given, allow + * the terminating NUL to limit + * operations. */ + + if (objc == 3) { + if (TCL_OK != TclGetIntForIndex(interp, objv[2], numBytes, &offset)) { + return TCL_ERROR; + } + if (offset < 0) { + offset = 0; + } + if (offset > numBytes + TCL_UTF_MAX) { + offset = numBytes + TCL_UTF_MAX; + } + } + if (numBytes > sizeof(buffer)-2) { - Tcl_AppendResult(interp, "\"testutfnext\" can only handle 30 bytes", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"testutfnext\" can only handle %d bytes", + sizeof(buffer) - 2)); return TCL_ERROR; } memcpy(buffer + 1, bytes, numBytes); buffer[0] = buffer[numBytes + 1] = '\x00'; + if (!Tcl_UtfCharComplete(buffer + 1, offset)) { + /* Cannot scan a complete sequence from the data */ + + Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); + return TCL_OK; + } + first = Tcl_UtfNext(buffer + 1); while ((buffer[0] = *p++) != '\0') { /* Run Tcl_UtfNext with many more possible bytes at src[-1], all should give the same result */ -- cgit v0.12 From 3b1c00722a2401b6c4a6f80044364f6365da9749 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 22 Apr 2020 22:18:53 +0000 Subject: Collection of tests checking read limit protections calling Tcl_UtfNext. --- generic/tclTest.c | 8 ++-- tests/utf.test | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 4 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index 76a827a..d00c852 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -7138,7 +7138,7 @@ TestUtfNextCmd( bytes = (char *) Tcl_GetByteArrayFromObj(objv[1], &numBytes); - offset = numBytes + TCL_UTF_MAX; /* If no constraint is given, allow + offset = numBytes +TCL_UTF_MAX -1; /* If no constraint is given, allow * the terminating NUL to limit * operations. */ @@ -7149,12 +7149,12 @@ TestUtfNextCmd( if (offset < 0) { offset = 0; } - if (offset > numBytes + TCL_UTF_MAX) { - offset = numBytes + TCL_UTF_MAX; + if (offset > numBytes +TCL_UTF_MAX -1) { + offset = numBytes +TCL_UTF_MAX -1; } } - if (numBytes > sizeof(buffer)-2) { + if (numBytes > sizeof(buffer) - 2) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "\"testutfnext\" can only handle %d bytes", sizeof(buffer) - 2)); diff --git a/tests/utf.test b/tests/utf.test index beba98c..5058cbf 100644 --- a/tests/utf.test +++ b/tests/utf.test @@ -448,6 +448,123 @@ test utf-6.92 {Tcl_UtfNext, pointing to 2th byte of 4-byte invalid sequence} tes test utf-6.93 {Tcl_UtfNext, pointing to 2th byte of 4-byte invalid sequence} testutfnext { testutfnext \x80\x80\x80 } 1 +test utf-6.94 {Tcl_UtfNext, read limits} testutfnext { + testutfnext G 0 +} 0 +test utf-6.95 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0 0 +} 0 +test utf-6.96 {Tcl_UtfNext, read limits} testutfnext { + testutfnext AG 1 +} 1 +test utf-6.97 {Tcl_UtfNext, read limits} testutfnext { + testutfnext A\xA0 1 +} 1 +test utf-6.98 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xD0\xA0G 1 +} 0 +test utf-6.99 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xD0\xA0G 2 +} 2 +test utf-6.100 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xD0\xA0\xA0 1 +} 0 +test utf-6.101 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xD0\xA0\xA0 2 +} 2 +test utf-6.102 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0G 1 +} 0 +test utf-6.103 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0G 2 +} 0 +test utf-6.104 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0G 3 +} 3 +test utf-6.105 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0\xA0 1 +} 0 +test utf-6.106 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0\xA0 2 +} 0 +test utf-6.107 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xE8\xA0\xA0\xA0 3 +} 3 +test utf-6.108.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0G 1 +} 1 +test utf-6.108.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0G 1 +} 0 +test utf-6.109.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0G 2 +} 1 +test utf-6.109.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0G 2 +} 0 +test utf-6.110.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0G 3 +} 1 +test utf-6.110.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0G 3 +} 0 +test utf-6.111.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0G 4 +} 1 +test utf-6.111.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0G 4 +} 4 +test utf-6.112.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0\xA0 1 +} 1 +test utf-6.112.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0\xA0 1 +} 0 +test utf-6.113.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0\xA0 2 +} 1 +test utf-6.113.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0\xA0 2 +} 0 +test utf-6.114.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0\xA0 3 +} 1 +test utf-6.114.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0\xA0 3 +} 0 +test utf-6.115.0 {Tcl_UtfNext, read limits} {testutfnext ucs2} { + testutfnext \xF2\xA0\xA0\xA0\xA0 4 +} 1 +test utf-6.115.1 {Tcl_UtfNext, read limits} {testutfnext fullutf} { + testutfnext \xF2\xA0\xA0\xA0\xA0 4 +} 4 +test utf-6.116 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0G 0 +} 0 +test utf-6.117 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0G 1 +} 1 +test utf-6.118 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0 1 +} 1 +test utf-6.119 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0G 2 +} 1 +test utf-6.120 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0\xA0 2 +} 1 +test utf-6.121 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0\xA0G 3 +} 1 +test utf-6.122 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0\xA0\xA0 3 +} 1 +test utf-6.121 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0\xA0\xA0G 4 +} 1 +test utf-6.122 {Tcl_UtfNext, read limits} testutfnext { + testutfnext \xA0\xA0\xA0\xA0\xA0 4 +} 1 test utf-7.1 {Tcl_UtfPrev} testutfprev { testutfprev {} -- cgit v0.12 From 6852f6d630fb0cbb7521dc006203efb9697bc815 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 22 Apr 2020 22:31:39 +0000 Subject: test number reuse --- tests/utf.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/utf.test b/tests/utf.test index 5058cbf..2c8a001 100644 --- a/tests/utf.test +++ b/tests/utf.test @@ -358,7 +358,7 @@ test utf-6.70 {Tcl_UtfNext} testutfnext { test utf-6.71 {Tcl_UtfNext} testutfnext { testutfnext \xF2\xA0\xA0\xE8 } 1 -test utf-6.71 {Tcl_UtfNext} testutfnext { +test utf-6.72 {Tcl_UtfNext} testutfnext { testutfnext \xF2\xA0\xA0\xF2 } 1 test utf-6.73 {Tcl_UtfNext} testutfnext { @@ -559,10 +559,10 @@ test utf-6.121 {Tcl_UtfNext, read limits} testutfnext { test utf-6.122 {Tcl_UtfNext, read limits} testutfnext { testutfnext \xA0\xA0\xA0\xA0 3 } 1 -test utf-6.121 {Tcl_UtfNext, read limits} testutfnext { +test utf-6.123 {Tcl_UtfNext, read limits} testutfnext { testutfnext \xA0\xA0\xA0\xA0G 4 } 1 -test utf-6.122 {Tcl_UtfNext, read limits} testutfnext { +test utf-6.124 {Tcl_UtfNext, read limits} testutfnext { testutfnext \xA0\xA0\xA0\xA0\xA0 4 } 1 -- cgit v0.12 From a9e7b242c6177d483c19da4f233e2792677300f7 Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 23 Apr 2020 14:52:10 +0000 Subject: documentation: descibes the empty list creation (with reserved space) where objv is NULL, like Tcl_NewListObj(n, NULL) --- doc/ListObj.3 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/ListObj.3 b/doc/ListObj.3 index c0cc109..a4f2a09 100644 --- a/doc/ListObj.3 +++ b/doc/ListObj.3 @@ -138,7 +138,9 @@ create a new object or modify an existing object to hold the \fIobjc\fR elements of the array referenced by \fIobjv\fR where each element is a pointer to a Tcl object. If \fIobjc\fR is less than or equal to zero, -they return an empty object. +they return an empty object. If \fIobjv\fR is NULL, the resulting list +contains 0 elements, with reserved space in an internal representation +for \fIobjc\fR more elements (to avoid its reallocation later). The new object's string representation is left invalid. The two procedures increment the reference counts of the elements in \fIobjc\fR since the list object now refers to them. -- cgit v0.12 From 6eb9a20757397e7b55ba203a87ecb54afe7f563d Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 23 Apr 2020 19:04:57 +0000 Subject: Argument conditions for Invalid() call were not always satisfied. --- generic/tclUtf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclUtf.c b/generic/tclUtf.c index 3741d70..550d528 100644 --- a/generic/tclUtf.c +++ b/generic/tclUtf.c @@ -660,7 +660,7 @@ Tcl_UtfNext( } next++; } - if (Invalid((unsigned char *)src)) { + if ((next == src + 1) || Invalid((unsigned char *)src)) { return src + 1; } return next; -- cgit v0.12 From 423df1f681b111dff8a5633b5aaa6e0049aaeddf Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 24 Apr 2020 12:26:09 +0000 Subject: Fix GCC warning in MemDebug mode: format not a string literal and no format arguments [-Wformat-security] --- generic/tclCkalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index 5263e82..b6616cd 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -187,7 +187,7 @@ TclDumpMemoryInfo(ClientData clientData, int flags) maximum_malloc_packets, (unsigned long)maximum_bytes_malloced); if (flags == 0) { - fprintf((FILE *)clientData, buf); + fprintf((FILE *)clientData, "%s", buf); } else { /* Assume objPtr to append to */ Tcl_AppendToObj((Tcl_Obj *) clientData, buf, -1); -- cgit v0.12