Tcl Source Code

View Ticket
Login
Ticket UUID: 3307281
Title: Tcl_SetStdChannel not respected by 'puts'
Type: Bug Version: obsolete: 8.5.9
Submitter: Created on: 2011-05-25 05:14:21
Subsystem: 25. Channel System Assigned To: andreas_kupries
Priority: 5 Medium Severity:
Status: Open Last Modified: 2011-05-26 00:35:27
Resolution: None Closed By:
    Closed on:
Description:
Hi all,

I'm using Tcl_SetStdChannel to redirect all output from my program+script to an external file. I noticed that some output of 'puts' is not being redirected. I'm not able to make a reduced test that covers both situations I see in my bigger program. Here is one that I was able to make that illustrates one of them.

In this reduced test: the command 'puts stdout <string>' gets redirected, but if I leave out 'stdout', it doesn't. However, in my real program I get a situation wherein redirection doesn't work even after explicitly specifying 'stdout'.

Having looked at the code, it seems like there are a couple of ways by which a string like 'stdout' is converted into a channel handle. These don't seem to be respecting Tcl_SetStdChannel. For the case where even specifying 'stdout' doesn't result in redirection in my real test, I noticed that the code satisfies test 'objPtr->typePtr == &tclChannelType' in SetChannelFromAny (tclIO.c).

Am I doing something wrong?

Thanks!
User Comments: added on 2011-05-26 00:35:27:
Hi ferrieux,

Thanks for the hint and the response. I dug around a little more and realized that the right fix is probably to invalidate the pointer to the stdout object that Tcl_PutsObjCmd maintains. I implemented it the most direct possible manner: Tcl_SetStdChannel will call a function in tclIOCmd.c to invalidate it's ThreadSpecificData.

I've attached the patch.

Not sure if this how inter-file communication should be handled etc. If you think this is the right fix, could you please clean it up and check it in?

Thanks a lot.
Ranga

added on 2011-05-26 00:31:53:

File Added - 412745: fix.patch

ferrieux added on 2011-05-25 14:22:41:
One more thing, when I say "the stdout value", clearly you have to be creative to put your hands on all of them. To analyse to what extent the literal is shared, look at the Tcl_Obj pointer. The following experiment at script level suggests that reasonable sharing can be expected at least with procs and constant "stdout":

% proc f {} {dputs stdout A}
% proc g {} {dputs stdout B}
% proc dputs {ch s} {
   puts $ch $s;puts REPR:[::tcl::unsupported::representation $ch]
}
% f
A
REPR:value is a channel with a refcount of 5, object pointer at 0x8b66560, internal representation 0x8b62180:0x8b38f58, string representation "stdout".
% g
B
REPR:value is a channel with a refcount of 6, object pointer at 0x8b66560, internal representation 0x8b62180:0x8b38f58, string representation "stdout".

ferrieux added on 2011-05-25 14:16:11:
Oh, I can see the logic: in the code path that you describe, the "stdout" value is first used when pointing to (say) Channel1, so as a side-effect of this access, an intrep of type Channel is computed and attached to it.
 Then you call Tcl_SetStdChannel(OUT,Channel2) but there is no easy way  to seek & destroy all instances of this association ("stdout", Channel1), so it remains in action.

If this interpretation is right, a workaround is to force a shimmer on the "stdout" value, eg by converting it to a List or simply invalidating the intrep since you're at C level. Then on next IO access, the intrep will be recomputed in accordance with the new redirection.

added on 2011-05-25 12:14:34:

File Added - 412664: tout5.c

Attachments: