Tcl Source Code

Check-in [e08c4afb53]
Login

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

Overview
Comment:Fix for [9ca87e6286262a62], sync fcopy buffers input in ReadChars().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | main
Files: files | file ages | folders
SHA3-256: e08c4afb5351744eb1973490d35c50c4f9bb97a6dad53eb57e1812a8ed06b482
User & Date: pooryorick 2023-04-03 17:13:19.561
References
2023-04-03
17:15 Pending ticket [9ca87e6286]: Sync fcopy buffers input in ReadChars() plus 5 other changes artifact: da17a3c374 user: pooryorick
Context
2023-04-04
16:26
Fix for [9ca87e6286262a62], sync fcopy buffers input in ReadChars(). check-in: ab027cdce4 user: pooryorick tags: core-8-branch
2023-04-03
19:58
Fix typo in test io-53.12.1. check-in: b154e3fedf user: pooryorick tags: trunk, main
17:13
Fix for [9ca87e6286262a62], sync fcopy buffers input in ReadChars(). check-in: e08c4afb53 user: pooryorick tags: trunk, main
17:12
Fix for [9ca87e6286262a62], sync fcopy buffers input in ReadChars(). check-in: 9498359f85 user: pooryorick tags: bug-9ca87e6286262a62f
2023-04-02
13:23
Bug [7e3f26c748] - TCL_MEM_DEBUG false positive check-in: f505b17748 user: apnadkarni tags: trunk, main
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclIO.c.
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static Tcl_Size		DoRead(Channel *chanPtr, char *dst, Tcl_Size bytesToRead,
			    int allowShortReads);
static Tcl_Size		DoReadChars(Channel *chan, Tcl_Obj *objPtr, Tcl_Size toRead,
			    int appendFlag);
static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int calledFromAsyncFlush);
static int		TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr);
static Tcl_Encoding	GetBinaryEncoding(void);
static Tcl_ExitProc	FreeBinaryEncoding;







|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static Tcl_Size		DoRead(Channel *chanPtr, char *dst, Tcl_Size bytesToRead,
			    int allowShortReads);
static Tcl_Size		DoReadChars(Channel *chan, Tcl_Obj *objPtr, Tcl_Size toRead,
			    int allowShortReads, int appendFlag);
static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int calledFromAsyncFlush);
static int		TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr);
static Tcl_Encoding	GetBinaryEncoding(void);
static Tcl_ExitProc	FreeBinaryEncoding;
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
	 * data in the buffers.
	 */

	UpdateInterest(chanPtr);
	return TCL_INDEX_NONE;
    }

    return DoReadChars(chanPtr, objPtr, toRead, appendFlag);
}
/*
 *---------------------------------------------------------------------------
 *
 * DoReadChars --
 *
 *	Reads from the channel until the requested number of characters have







|







5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
	 * data in the buffers.
	 */

	UpdateInterest(chanPtr);
	return TCL_INDEX_NONE;
    }

    return DoReadChars(chanPtr, objPtr, toRead, 0, appendFlag);
}
/*
 *---------------------------------------------------------------------------
 *
 * DoReadChars --
 *
 *	Reads from the channel until the requested number of characters have
5926
5927
5928
5929
5930
5931
5932

5933
5934
5935
5936
5937
5938
5939
static Tcl_Size
DoReadChars(
    Channel *chanPtr,		/* The channel to read. */
    Tcl_Obj *objPtr,		/* Input data is stored in this object. */
    Tcl_Size toRead,		/* Maximum number of characters to store, or
				 * TCL_INDEX_NONE to read all available data (up to EOF or
				 * when channel blocks). */

    int appendFlag)		/* If non-zero, data read from the channel
				 * will be appended to the object. Otherwise,
				 * the data will replace the existing contents
				 * of the object. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */







>







5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
static Tcl_Size
DoReadChars(
    Channel *chanPtr,		/* The channel to read. */
    Tcl_Obj *objPtr,		/* Input data is stored in this object. */
    Tcl_Size toRead,		/* Maximum number of characters to store, or
				 * TCL_INDEX_NONE to read all available data (up to EOF or
				 * when channel blocks). */
    int allowShortReads,	/* Allow half-blocking (pipes,sockets) */
    int appendFlag)		/* If non-zero, data read from the channel
				 * will be appended to the object. Otherwise,
				 * the data will replace the existing contents
				 * of the object. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
	    }
	}

	if (copiedNow < 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF)) {
		break;
	    }
	    if (GotFlag(statePtr, CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)
		    == (CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)) {
		break;
	    }
	    result = GetInput(chanPtr);
	    if (chanPtr != statePtr->topChanPtr) {
		TclChannelRelease((Tcl_Channel)chanPtr);
		chanPtr = statePtr->topChanPtr;
		TclChannelPreserve((Tcl_Channel)chanPtr);







|
|







6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
	    }
	}

	if (copiedNow < 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF)) {
		break;
	    }
	    if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads)
		    && GotFlag(statePtr, CHANNEL_BLOCKED)) {
		break;
	    }
	    result = GetInput(chanPtr);
	    if (chanPtr != statePtr->topChanPtr) {
		TclChannelRelease((Tcl_Channel)chanPtr);
		chanPtr = statePtr->topChanPtr;
		TclChannelPreserve((Tcl_Channel)chanPtr);
9758
9759
9760
9761
9762
9763
9764

9765
9766
9767
9768
9769
9770
9771
9772
	    }

	    if (inBinary || sameEncoding) {
		size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
                              !GotFlag(inStatePtr, CHANNEL_NONBLOCKING));
	    } else {
		size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,

			0 /* No append */);
	    }
	    underflow = (size >= 0) && ((size_t)size < sizeb);	/* Input underflow */
	}

	if (size < 0) {
	readError:
	    if (interp) {







>
|







9759
9760
9761
9762
9763
9764
9765
9766
9767
9768
9769
9770
9771
9772
9773
9774
	    }

	    if (inBinary || sameEncoding) {
		size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
                              !GotFlag(inStatePtr, CHANNEL_NONBLOCKING));
	    } else {
		size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,
			!GotFlag(inStatePtr, CHANNEL_NONBLOCKING)
			,0 /* No append */);
	    }
	    underflow = (size >= 0) && ((size_t)size < sizeb);	/* Input underflow */
	}

	if (size < 0) {
	readError:
	    if (interp) {
Changes to tests/io.test.
8272
8273
8274
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297


























8298
8299
8300
8301
8302
8303
8304
    set done
} -cleanup {
    close $outChan
    close $inChan
    removeFile out
    removeFile in
} -result {40 bytes copied}
test io-53.12 {CopyData: foreground short reads, aka bug 3096275} {stdio unix fcopy} {
    file delete $path(pipe)
    set f1 [open $path(pipe) w]
    puts -nonewline $f1 {
	fconfigure stdin -translation binary -blocking 0
	fconfigure stdout -buffering none -translation binary
	fcopy stdin stdout
    }
    close $f1
    set f1 [open "|[list [interpreter] $path(pipe)]" r+]
    fconfigure $f1 -translation binary -buffering none
    puts -nonewline $f1 A
    after 2000 {set ::done timeout}
    fileevent $f1 readable {set ::done ok}
    vwait ::done
    set ch [read $f1 1]
    close $f1
    list $::done $ch
} {ok A}


























test io-53.13 {TclCopyChannel: read error reporting} -setup {
    proc driver {cmd args} {
        variable buffer
        variable index
        set chan [lindex $args 0]
        switch -- $cmd {
            initialize {







|


















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







8272
8273
8274
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
    set done
} -cleanup {
    close $outChan
    close $inChan
    removeFile out
    removeFile in
} -result {40 bytes copied}
test io-53.12.0 {CopyData: foreground short reads, aka bug 3096275} {stdio unix fcopy} {
    file delete $path(pipe)
    set f1 [open $path(pipe) w]
    puts -nonewline $f1 {
	fconfigure stdin -translation binary -blocking 0
	fconfigure stdout -buffering none -translation binary
	fcopy stdin stdout
    }
    close $f1
    set f1 [open "|[list [interpreter] $path(pipe)]" r+]
    fconfigure $f1 -translation binary -buffering none
    puts -nonewline $f1 A
    after 2000 {set ::done timeout}
    fileevent $f1 readable {set ::done ok}
    vwait ::done
    set ch [read $f1 1]
    close $f1
    list $::done $ch
} {ok A}
test io-53.12.1 {
    Issue 9ca87e6286262a62.
    CopyData: foreground short reads via ReadChars().
    Related to report 3096275 for ReadBytes().

    Prior to the fix this test waited forever for read() to return.
} {stdio unix fcopy} {
    file delete $path(output)
    set f1 [open $path(output) w]
    puts -nonewline $f1 {
	chan configure stdin -encoding iso8859-1 -translation lf -buffering none
	fcopy stdin stdout
    }
    close $f1
    set f1 [open "|[list [info nameofexecutable] $path(output)]" r+]
    try {
	chan configure $f1 -encoding utf-6  -buffering none
	puts -nonewline $f1 A
	set ch [read $f1 1]
    } finally {
	if {$f1 in [chan names]} {
	    close $f1
	}
    }
    lindex $ch
} A
test io-53.13 {TclCopyChannel: read error reporting} -setup {
    proc driver {cmd args} {
        variable buffer
        variable index
        set chan [lindex $args 0]
        switch -- $cmd {
            initialize {