Tcl Source Code

Check-in [4c19c39276]
Login

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

Overview
Comment:Merge minimal fix for iocmd-23.11. Note that top channel regeneration is removed, so that Preserve/Release call pairs are sure to operate on the same pointers. Other bug fixes may need to change that.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:4c19c3927610d872576317bfddcb42676c0bc982
User & Date: dgp 2014-03-28 20:29:03
Context
2014-03-31
18:44
Add missing @TCL_LIB_FLAG@ to tcl.pc.in (derived from ticket [5bcb5026ad]) check-in: 85f74e89a1 user: jan.nijtmans tags: trunk
08:09
merge trunk check-in: 0f642ee045 user: dkf tags: dkf-http-cookies
2014-03-28
20:29
Merge minimal fix for iocmd-23.11. Note that top channel regeneration is removed, so that Preserve/R... check-in: 4c19c39276 user: dgp tags: trunk
2014-03-27
21:35
Minimal patch to fix iocmd-23.11. Might not be the best fix, but is *a* fix. check-in: b846182cdc user: dgp tags: core-8-5-branch
19:15
Test iocmd-23.11 demos another segfault. check-in: 045e8076eb user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclIO.c.

4257
4258
4259
4260
4261
4262
4263

4264
4265
4266
4267
4268
4269
4270
....
4489
4490
4491
4492
4493
4494
4495
4496

4497

4498
4499
4500
4501
4502
4503
4504
....
4524
4525
4526
4527
4528
4529
4530
4531

4532
4533

4534
4535
4536
4537
4538
4539
4540
....
4566
4567
4568
4569
4570
4571
4572
4573

4574
4575

4576

4577
4578
4579
4580
4581
4582
4583
....
4615
4616
4617
4618
4619
4620
4621

4622
4623
4624
4625
4626
4627
4628
....
4818
4819
4820
4821
4822
4823
4824

4825
4826
4827
4828
4829
4830
4831
....
5290
5291
5292
5293
5294
5295
5296

5297
5298
5299
5300
5301
5302
5303
....
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387

5388
5389
5390

5391
5392
5393
5394

5395
5396
5397
5398
5399
5400
5401
....
5495
5496
5497
5498
5499
5500
5501

5502
5503
5504
5505
5506
5507
5508
....
5586
5587
5588
5589
5590
5591
5592
5593

5594
5595

5596

5597
5598
5599
5600
5601
5602
5603
....
8097
8098
8099
8100
8101
8102
8103





8104
8105
8106
8107
8108
8109
8110
....
9201
9202
9203
9204
9205
9206
9207

9208
9209
9210
9211
9212
9213
9214
....
9241
9242
9243
9244
9245
9246
9247

9248
9249
9250
9251
9252
9253
9254
    }

    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;


    bufPtr = statePtr->inQueueHead;
    encoding = statePtr->encoding;

    /*
     * Preserved so we can restore the channel's state in case we don't find a
     * newline in the available input.
................................................................................
     */

  gotEOL:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */


    chanPtr = statePtr->topChanPtr;


    bufPtr = gs.bufPtr;
    if (bufPtr == NULL) {
	Tcl_Panic("Tcl_GetsObj: gotEOL reached with bufPtr==NULL");
    }
    statePtr->inputEncodingState = gs.state;
    Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), gs.rawRead,
................................................................................
     */

  restore:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */


    chanPtr = statePtr->topChanPtr;


    bufPtr = statePtr->inQueueHead;
    if (bufPtr == NULL) {
	Tcl_Panic("Tcl_GetsObj: restore reached with bufPtr==NULL");
    }
    bufPtr->nextRemoved = oldRemoved;

    for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) {
................................................................................
     */

  done:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */


    chanPtr = statePtr->topChanPtr;


    UpdateInterest(chanPtr);

    return copiedTotal;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * TclGetsObjBinary --
................................................................................
    unsigned char *dst, *dstEnd, *eol, *eof, *byteArray;

    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;


    bufPtr = statePtr->inQueueHead;

    /*
     * Preserved so we can restore the channel's state in case we don't find a
     * newline in the available input.
     */
................................................................................
    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.
     */

  done:
    UpdateInterest(chanPtr);

    return copiedTotal;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * FreeBinaryEncoding --
................................................................................

    /*
     * Check for information in the push-back buffers. If there is some, use
     * it. Go to the driver only if there is none (anymore) and the caller
     * requests more bytes.
     */


    for (copied = 0; copied < bytesToRead; copied += copiedNow) {
	copiedNow = CopyBuffer(chanPtr, bufPtr + copied,
		bytesToRead - copied);
	if (copiedNow == 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF)) {
		goto done;
	    }
................................................................................
		if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
		    if (copied > 0) {
			/*
			 * Information that was copied earlier has precedence
			 * over EAGAIN/WOULDBLOCK handling.
			 */

			return copied;
		    }

		    SetFlag(statePtr, CHANNEL_BLOCKED);
		    result = EAGAIN;
		}

		Tcl_SetErrno(result);
		return -1;

	    }

	    return copied + nread;

	}
    }

  done:

    return copied;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * Tcl_ReadChars --
................................................................................
    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;
    encoding = statePtr->encoding;
    factor = UTF_EXPANSION_FACTOR;


    if (appendFlag == 0) {
	if (encoding == NULL) {
	    Tcl_SetByteArrayLength(objPtr, 0);
	} else {
	    Tcl_SetObjLength(objPtr, 0);

................................................................................
     */

  done:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */


    chanPtr = statePtr->topChanPtr;


    UpdateInterest(chanPtr);

    return copied;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * ReadBytes --
................................................................................
static void
UpdateInterest(
    Channel *chanPtr)		/* Channel to update. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    int mask = statePtr->interestMask;






    /*
     * If there are flushed buffers waiting to be written, then we need to
     * watch for the channel to become writable.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
................................................................................

    /*
     * If we have not encountered a sticky EOF, clear the EOF bit. Either way
     * clear the BLOCKED bit. We want to discover these anew during each
     * operation.
     */


    if (!GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
	ResetFlag(statePtr, CHANNEL_EOF);
    }
    ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA);

    for (copied = 0; copied < toRead; copied += copiedNow) {
	copiedNow = CopyAndTranslateBuffer(statePtr, bufPtr + copied,
................................................................................
    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.
     */

  done:
    UpdateInterest(chanPtr);

    return copied;
}
 
/*
 *----------------------------------------------------------------------
 *
 * CopyAndTranslateBuffer --







>







 







<
>

>







 







<
>

<
>







 







<
>

<
>

>







 







>







 







>







 







>







 







|







|
>


|
>




>







 







>







 







<
>

<
>

>







 







>
>
>
>
>







 







>







 







>







4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
....
4490
4491
4492
4493
4494
4495
4496

4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
....
4526
4527
4528
4529
4530
4531
4532

4533
4534

4535
4536
4537
4538
4539
4540
4541
4542
....
4568
4569
4570
4571
4572
4573
4574

4575
4576

4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
....
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
....
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
....
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
....
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
....
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
....
5596
5597
5598
5599
5600
5601
5602

5603
5604

5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
....
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118
8119
8120
8121
8122
8123
8124
8125
8126
....
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
....
9258
9259
9260
9261
9262
9263
9264
9265
9266
9267
9268
9269
9270
9271
9272
    }

    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;
    Tcl_Preserve(chanPtr);

    bufPtr = statePtr->inQueueHead;
    encoding = statePtr->encoding;

    /*
     * Preserved so we can restore the channel's state in case we don't find a
     * newline in the available input.
................................................................................
     */

  gotEOL:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */

    /*
    chanPtr = statePtr->topChanPtr;
     */

    bufPtr = gs.bufPtr;
    if (bufPtr == NULL) {
	Tcl_Panic("Tcl_GetsObj: gotEOL reached with bufPtr==NULL");
    }
    statePtr->inputEncodingState = gs.state;
    Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), gs.rawRead,
................................................................................
     */

  restore:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */

    /*
    chanPtr = statePtr->topChanPtr;

     */
    bufPtr = statePtr->inQueueHead;
    if (bufPtr == NULL) {
	Tcl_Panic("Tcl_GetsObj: restore reached with bufPtr==NULL");
    }
    bufPtr->nextRemoved = oldRemoved;

    for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) {
................................................................................
     */

  done:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */

    /*
    chanPtr = statePtr->topChanPtr;

     */
    UpdateInterest(chanPtr);
    Tcl_Release(chanPtr);
    return copiedTotal;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * TclGetsObjBinary --
................................................................................
    unsigned char *dst, *dstEnd, *eol, *eof, *byteArray;

    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;
    Tcl_Preserve(chanPtr);

    bufPtr = statePtr->inQueueHead;

    /*
     * Preserved so we can restore the channel's state in case we don't find a
     * newline in the available input.
     */
................................................................................
    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.
     */

  done:
    UpdateInterest(chanPtr);
    Tcl_Release(chanPtr);
    return copiedTotal;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * FreeBinaryEncoding --
................................................................................

    /*
     * Check for information in the push-back buffers. If there is some, use
     * it. Go to the driver only if there is none (anymore) and the caller
     * requests more bytes.
     */

    Tcl_Preserve(chanPtr);
    for (copied = 0; copied < bytesToRead; copied += copiedNow) {
	copiedNow = CopyBuffer(chanPtr, bufPtr + copied,
		bytesToRead - copied);
	if (copiedNow == 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF)) {
		goto done;
	    }
................................................................................
		if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
		    if (copied > 0) {
			/*
			 * Information that was copied earlier has precedence
			 * over EAGAIN/WOULDBLOCK handling.
			 */

			goto done;
		    }

		    SetFlag(statePtr, CHANNEL_BLOCKED);
		    result = EAGAIN;
		}

		Tcl_SetErrno(result);
		copied = -1;
		goto done;
	    }

	    copied += nread;
	    goto done;
	}
    }

  done:
    Tcl_Release(chanPtr);
    return copied;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * Tcl_ReadChars --
................................................................................
    /*
     * This operation should occur at the top of a channel stack.
     */

    chanPtr = statePtr->topChanPtr;
    encoding = statePtr->encoding;
    factor = UTF_EXPANSION_FACTOR;
    Tcl_Preserve(chanPtr);

    if (appendFlag == 0) {
	if (encoding == NULL) {
	    Tcl_SetByteArrayLength(objPtr, 0);
	} else {
	    Tcl_SetObjLength(objPtr, 0);

................................................................................
     */

  done:
    /*
     * Regenerate the top channel, in case it was changed due to
     * self-modifying reflected transforms.
     */

    /*
    chanPtr = statePtr->topChanPtr;

     */
    UpdateInterest(chanPtr);
    Tcl_Release(chanPtr);
    return copied;
}
 
/*
 *---------------------------------------------------------------------------
 *
 * ReadBytes --
................................................................................
static void
UpdateInterest(
    Channel *chanPtr)		/* Channel to update. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    int mask = statePtr->interestMask;

    if (chanPtr->typePtr == NULL) {
	/* Do not update interest on a closed channel */
	return;
    }

    /*
     * If there are flushed buffers waiting to be written, then we need to
     * watch for the channel to become writable.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
................................................................................

    /*
     * If we have not encountered a sticky EOF, clear the EOF bit. Either way
     * clear the BLOCKED bit. We want to discover these anew during each
     * operation.
     */

    Tcl_Preserve(chanPtr);
    if (!GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
	ResetFlag(statePtr, CHANNEL_EOF);
    }
    ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA);

    for (copied = 0; copied < toRead; copied += copiedNow) {
	copiedNow = CopyAndTranslateBuffer(statePtr, bufPtr + copied,
................................................................................
    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.
     */

  done:
    UpdateInterest(chanPtr);
    Tcl_Release(chanPtr);
    return copied;
}
 
/*
 *----------------------------------------------------------------------
 *
 * CopyAndTranslateBuffer --

Changes to generic/tclIORChan.c.

582
583
584
585
586
587
588

589
590
591
592
593
594
595
....
2302
2303
2304
2305
2306
2307
2308

2309
2310
2311
2312
2313
2314
2315
     */

    rcId = NextHandle();
    rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId);
    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
	    mode);
    rcPtr->chan = chan;

    chanPtr = (Channel *) chan;

    /*
     * Invoke 'initialize' and validate that the handler is present and ok.
     * Squash the channel if not.
     *
     * Note: The conversion of 'mode' back into a Tcl_Obj ensures that
................................................................................
	/*
	 * Delete a cloned ChannelType structure.
	 */

	ckfree(chanPtr->typePtr);
	chanPtr->typePtr = NULL;
    }


    FreeReflectedChannelArgs(rcPtr);

    ckfree(rcPtr->argv);
    ckfree(rcPtr);
}
 







>







 







>







582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
....
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
     */

    rcId = NextHandle();
    rcPtr = NewReflectedChannel(interp, cmdObj, mode, rcId);
    chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
	    mode);
    rcPtr->chan = chan;
    Tcl_Preserve(chan);
    chanPtr = (Channel *) chan;

    /*
     * Invoke 'initialize' and validate that the handler is present and ok.
     * Squash the channel if not.
     *
     * Note: The conversion of 'mode' back into a Tcl_Obj ensures that
................................................................................
	/*
	 * Delete a cloned ChannelType structure.
	 */

	ckfree(chanPtr->typePtr);
	chanPtr->typePtr = NULL;
    }
    Tcl_Release(chanPtr);

    FreeReflectedChannelArgs(rcPtr);

    ckfree(rcPtr->argv);
    ckfree(rcPtr);
}
 

Changes to tests/ioCmd.test.

1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
	set args [lassign $args sub id]
	if {$sub ne "read"} {return}
	close $id
	return {}
    }
    set c [chan create {r} foo]
    note [read $c]
    close $c
    rename foo {}
    set res
} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}

# --- === *** ###########################
# method write

test iocmd-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {







<


|







1058
1059
1060
1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
	set args [lassign $args sub id]
	if {$sub ne "read"} {return}
	close $id
	return {}
    }
    set c [chan create {r} foo]
    note [read $c]

    rename foo {}
    set res
} -result {{read rc* 4096} {}}

# --- === *** ###########################
# method write

test iocmd-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {