SourceForge has been redesigned. Learn more.
Close

#1900 std channel refcount error when wish is child process

obsolete: 8.5a3
closed-fixed
9
2006-06-05
2005-04-27
Don Porter
No

Attempt to distill the useful bits
of information from report 1186042
into a new report here.

Discussion

1 2 > >> (Page 1 of 2)
  • Don Porter

    Don Porter - 2005-04-27

    Logged In: YES
    user_id=80530

    When line 201 of revision 1.22
    of tkConsole.c is reached, a
    prior call to Tcl_GetStdChannel()
    has returned a non-NULL Tcl_Channel,
    and an internal refcount in the Tcl_Channel
    has been incremented.

    Somehow this increment is one more
    than the finalization code of Tcl expects,
    and Tcl fails to close the system side
    of the channel(s) during app shutdown.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Program starts in WinMain,
    where consoleRequired is
    set to TRUE.

    Then, Tk_MainEx calls
    Tcl_FindExecutable. The
    system encoding gets
    initialized, which involves
    reading from a *.enc file.
    Opening that file channel
    involves a call to Tcl_CreateChannel.
    At the end of Tcl_CreateChannel,
    the file channel to the encoding
    file becomes "stdin".

    ok, that's... weird.

    All the cp* encodings that can be
    [encoding system] values on
    Windows are not escape encodings,
    so there's only the one file channel
    to worry about.

    After the encoding data is read,
    Tcl_Close is called.
    CheckForStdChannelIsBeingClosed
    sees a refCount of 1, and resets
    "stdin" to be undefined.

    So, I think that's weird, but unrelated
    to the symptoms reported.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Oops, there I go with the false
    info again.

    The auto-setting of std channels
    in Tcl_CreateChannel only happens
    for each std channel after it has
    been "initialized". So this mechanism
    can refill a lost std channel, but won't
    establish an initial one.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Moving on then, Tcl_FindExecutable
    returns, then Tk_InitConsoleChannels
    -> ShouldUseConsoleChannel
    -> Tcl_GetStdChannel.

    Presumably, this creates all 3 standard
    channels, bumps all refCounts to 1,
    and SUCC returns 0 all three times?

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Then back to Tk_MainEx
    and through lots of command line
    parsing code that's not relevant.
    Skip down to line 206, and note
    the comment "This probably isn't
    the right way to do it. " hmmmm...

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    So the logic of
    ShouldUseConsoleChannel(TCL_STDIN)
    is reproduced in Tk_MainEx. LIkely
    candidate for a good refactoring.

    Under the assumptions of the bug report,
    I think we can conclude that tsdPtr->tty
    will be 0, and so will tcl_interactive.

    Then on to the Tcl_AppInit call...

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Tcl_Init is called, but that does
    nothing with std channels.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Tk_Init does a [tcl_findLibrary],
    which triggers the auto-loader,
    and [auto_load_index] calls
    [open] on each tclIndex file.
    A side effect of [open] is to
    register stdin, stdout, stderr
    in the interp, bumping the
    refcount of each one.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    then, because consoleRequired is TRUE
    (remember?), we call Tk_CreateConsoleWindow.

    This feels like an error. We actually do have
    working standard channels, it appears, yet now
    we're creating a [console] widget that won't work.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Tk_CreateConsoleWindow creates
    another interp, and calls Tcl_Init
    and Tk_Init on it, registering
    the std* channels again, bumping
    refcounts to 3.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    Effectively, then, the std* channels
    are [interp share]d channels, and
    you need to [close] them in each
    interp (or delete each interp) in order
    to really close them.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    This verifies require Tk to
    demonstrate this "misfeature"
    of Tcl's standard channels.

    Create two interps in one app,
    register std* channels in both,
    and then the real closing function
    of Tcl_Close during exit is
    disabled, I suspect. Still figuring
    this out, and time to call it a day.

     
  • Don Porter

    Don Porter - 2005-04-28

    Logged In: YES
    user_id=80530

    See 1192047 for a report of
    the Tcl side of this error.

     
  • MKS

    MKS - 2005-04-29

    Logged In: YES
    user_id=1260469

    > At the end of Tcl_CreateChannel,
    > the file channel to the encoding
    > file becomes "stdin".

    As you caught yourself later, when no channels are open, the
    std channels get assigned to whatever becomes available.

    > Moving on then, Tcl_FindExecutable
    > returns, then Tk_InitConsoleChannels
    > -> ShouldUseConsoleChannel
    > -> Tcl_GetStdChannel.
    >
    > Presumably, this creates all 3 standard
    > channels, bumps all refCounts to 1,
    > and SUCC returns 0 all three times?

    Yes.

    > Skip down to line 206, and note
    > the comment "This probably isn't
    > the right way to do it. " hmmmm...

    I saw that, too. It's not anything that causes the refCount
    to get incremented, but it may have something to do with the
    recent post to CLT about the Eclipse editor interaction.
    ALWAYS assuming that the Tk console is to be used may indeed
    be the wrong thing -- perhaps there are cases, where a
    parent application has explicitly grabbed stdio channels,
    that Tk console should not be allowed? Or would that just
    make things MORE confusing? What is the "right" thing to
    do? Disallow Tk console under these circumstances?
    (confusing.) Duplicate behavior between Tk console and
    stdio channels so all input from both is handled, and all
    output goes to both? (confusing, but perhaps less so.)

    > Tk_CreateConsoleWindow creates
    > another interp, and calls Tcl_Init
    > and Tk_Init on it, registering
    > the std* channels again, bumping
    > refcounts to 3.

    Would it be out of line to ask what "two" interps exist at
    this point? There's obviously the main interp that acts as
    {} upon startup... what's the second?

    > Effectively, then, the std* channels
    > are [interp share]d channels, and
    > you need to [close] them in each
    > interp (or delete each interp) in order
    > to really close them.

    How? What is the "second" interp? Issuing:
    console eval {close stdout}
    close stdout

    Doesn't do it. The second statement just gets an error, and
    the "real" stdout pipe channel isn't actually closed.

    > This verifies require Tk to
    > demonstrate this "misfeature"
    > of Tcl's standard channels.

    Yes. And not only does it require Tk, but it requires
    "wish.exe," rather than tclsh with [package require Tk].
    Otherwise I believe you skip Tk_InitConsoleChannels entirely.

     
  • Don Porter

    Don Porter - 2005-04-29

    Logged In: YES
    user_id=80530

    The first interp is created as part
    of the Tk_Main() macro.

    The second interp is created
    within Tk_CreateConsoleWindow.

    console eval {close stdout}
    close stdout

    ought to be enough to really close
    the system stdout; If you don't see
    that happening, check to verify that
    the FileCloseProc in tclWinChan.c
    is getting called. (or ConsoleCloseProc
    in tclWinConsole.c if that's appropriate ?)

     
  • Nobody/Anonymous

    Logged In: NO

    > console eval {close stdout}
    > close stdout

    > ought to be enough to really close
    > the system stdout;

    That "works," in the sense that it does force the system stdout
    handles, and the "child" wish disconnects from the parent
    process.
    Personally, I think it's ugly, because essentially wish.exe has
    "two" consoles -- the Tk console that doesn't work, yet has an
    interp associated with it, whose channels must be closed,
    and the
    "main" interp's channels.

    Also...

    > I think we can conclude that tsdPtr->tty
    > will be 0, and so will tcl_interactive.

    tty is 0. Which seems "incorrect," as the description says
    that if it's 0, it's a file.

    So at this point, Tcl_Interactive should be 1, and tty, I
    think, should depend on wether or not it really is (if
    invoked with a file argument), yet consoleRequired should be
    0, so that Tk_CreateConsoleWindow should not be called?

    consoleRequired is a static Bool in winMain.c so it's
    inaccessible in tkConsole.c where it is determined that it
    should be 0.

     
  • Nobody/Anonymous

    Logged In: NO

    Tcl_Interactive should be 1, and tty, I think,
    should depend on wether or not it really is

    I got those reversed. tty should be 1, and tcl_interactive
    should depend on whether or not it really is.

     
  • Don Porter

    Don Porter - 2005-05-03

    Logged In: YES
    user_id=80530

    "Personally, I think it's ugly,..."

    Yes, I didn't mean that to be an answer.
    Just a test to make sure I understand
    what's going on on your system.

    BTW, this report is for Tk 8.5a3.
    Do you see the same trouble with
    Tk 8.4.9 ? I'm curious why this has
    become an issue now, and hasn't
    been one for the past few years.

     
  • MKS

    MKS - 2005-05-03

    Logged In: YES
    user_id=1260469

    > "Personally, I think it's ugly,..."

    > Yes, I didn't mean that to be an answer.
    > Just a test to make sure I understand
    > what's going on on your system.

    Your understanding is correct, then.

    > BTW, this report is for Tk 8.5a3.
    > Do you see the same trouble with
    > Tk 8.4.9 ?

    Oh, absolutely, yes. I've been doing all of my testing on 8.4.9
    sources. That's where it came up.

    > I'm curious why this has
    > become an issue now, and hasn't
    > been one for the past few years.

    I would venture a guess that: "nobody ever tried that before."

    Or tried, and never said anything, because it's Windows, and
    who expects Win32 applications to use std channels?

    And someone did just recently run across the "broken Tk console"
    side effect over in CLT.

    After all, it works using tclsh.exe, and it works in X11,
    where there is no Tk Console.

    Incidentally, it also effects Tcl/Tk Aqua on OS X. I
    haven't dug
    into that side of it yet, because I haven't quite figured
    out how to
    force it to use a specific set of frameworks.

    What can I say? I have a nack for finding really strange bugs.

    That said, further playing around reveals:

    1. stdPtr->tty is being determined to be 0, though it should
    be 1.
    This is REQUIRED for tcl/tk to output the prompt to stdout.

    2. consoleRequired should be 0, though it is "always" 1 for
    Wish.exe.

    For testing purposes, I did the following:

    Changed the return type of Tk_InitConsoleChannels() to int, and
    return a flag if ShouldUseConsoleChannel() ever returns 1.

    If the return value of Tk_InitConsoleChannels() does not
    contain the
    flag, then set stdPtr->tty to 1, rather than defaulting to 0.

    Use interp->errorLine to pass a message to Tcl_AppInit.
    First thing
    in Tcl_AppInit, before the interp gets initialized, if
    errorLine==1,
    then set consoleRequired to 0. Yes, this is sloppy, ugly,
    and just
    plain wrong, but:

    consoleRequired is static to winMain.c, and cannot be written
    from tkMain.c/Tk_MainEx().

    for testing purporses, it works.

    Results:

    No effect to "normal" startup. That is, doing this doesn't
    break
    anything.

    With stdPtr->tty set properly to 1, and consoleRequired set
    properly
    to 0, then Wish behaves "as expected," closing std channels when
    requested, and not creating a "broken" Tk console.

    There is an interesting side-effect, though -- something I
    noticed
    when running tclsh.exe in a debugger:

    The wish.exe application "blocks" -- does not start processing
    events, until it gets input from stdin. Once before the intial
    toplevel is created, and once again before the toplevel starts
    responding to events.

    Why?

     
  • Don Porter

    Don Porter - 2005-11-21

    Logged In: YES
    user_id=80530

    hoping to fix this for 8.4.12

     
  • Don Porter

    Don Porter - 2005-11-21
    • priority: 5 --> 9
     
  • Jeffrey Hobbs

    Jeffrey Hobbs - 2005-12-08

    Logged In: YES
    user_id=72656

    See also [ 912571 ] wish crashing during exit when stdin is
    closed.

     
  • Don Porter

    Don Porter - 2006-03-21

    Logged In: YES
    user_id=80530

    I think this one is now
    fixed on the Tk HEAD, but
    I need Windows testing to
    confirm that before I
    attempt a backport for 8.4.13.

     
  • Don Porter

    Don Porter - 2006-03-27

    Logged In: YES
    user_id=80530

    anyone? anyone? Bueller?

     
  • Don Porter

    Don Porter - 2006-06-05

    Logged In: YES
    user_id=80530

    I believe this issue is now
    resolved in 8.4.14 and 8.5a5.

    If that is not correct, please
    open a completely new bug report,
    and include in the new report
    simple and clear instructions on
    how to demonstrate the bug.

     
1 2 > >> (Page 1 of 2)