#4833 Tcl_SetStdChannel not respected by 'puts'

obsolete: 8.5.9

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?



  • Anonymous

    reduced test.

  • 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.

  • 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
    REPR:value is a channel with a refcount of 5, object pointer at 0x8b66560, internal representation 0x8b62180:0x8b38f58, string representation "stdout".
    % g
    REPR:value is a channel with a refcount of 6, object pointer at 0x8b66560, internal representation 0x8b62180:0x8b38f58, string representation "stdout".


  • Anonymous

    core of a potential fix for this bug. needs to made to conform to Tcl coding style.


  • Anonymous

    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.