Tk Source Code

View Ticket
Login
2005-04-19
22:24 Closed ticket [1184104fff]: Child Process Wish.exe Refuses to Close STDIO Channels plus 8 other changes artifact: 411791628d user: dgp
15:17 Ticket [1184104fff]: 1 change artifact: 2d6acbfa3a user: dkf
2005-04-18
21:50 Ticket [1184104fff]: 4 changes artifact: 4eb84a76b6 user: dgp
2005-04-16
20:51 Ticket [1184104fff]: 4 changes artifact: 02b524aa1c user: m_schrumpf
11:35 Ticket [1184104fff]: 4 changes artifact: 190511e2d0 user: dgp
10:52 Ticket [1184104fff]: 4 changes artifact: 249a3a850b user: m_schrumpf
10:45 Ticket [1184104fff]: 4 changes artifact: bd5daf66af user: nobody
10:43 Ticket [1184104fff]: 4 changes artifact: fa269be522 user: nobody
01:20 New ticket [1184104fff]. artifact: 49d6f94c1a user: nobody

Ticket UUID: 1184104
Title: Child Process Wish.exe Refuses to Close STDIO Channels
Type: Patch Version: None
Submitter: nobody Created on: 2005-04-16 01:20:43
Subsystem: 54. [console] Assigned To: dgp
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2005-04-19 22:24:07
Resolution: Duplicate Closed By: dgp
    Closed on: 2005-04-19 15:24:07
Description:
The problem lies in tkConsole/Tk_InitConsoleChannels()
within ShouldUseConsoleChannel().  When wish.exe is
started by double-clicking in Windows Explorer, or by
typing "wish" on the command line, it is detached from
the calling process' stdio channels.  When
ShouldUseConsoleChannel() is called, it returns 1,
bailing out early at handle==INVALID_HANDLE_VALUE, ==0,
or FILE_TYPE_UNKNOWN.

However, if the parent process does NOT relinquish
control of stdio channels, as with using
CreateProcess() and inheritable pipes assigned to the
child's stdio, then ShouldUseConsoleChannel() makes it
all the way to the call to Tcl_GetStdChannel(), which
increments the refCount.

By the end of initialization, refCount is at 3.  When
[close] is called on a given channel, DetachChannel()
decrements refCount to 2. 
CheckForStdChannelsBeingClosed() sees a refCount of 2,
and refuses to set refCount to 0, [incorrectly]
presuming that a second interp has the stdio channel open.

The fix is to decrement the refCount immediately if
Tcl_GetStdChannel() is reached.
User Comments: dgp added on 2005-04-19 22:24:07:
Logged In: YES 
user_id=80530

re-opened as Bug 1186042

dgp added on 2005-04-18 21:50:32:
Logged In: YES 
user_id=80530


If you submit a new report while logged in,
you'll be able to attach the patch.

m_schrumpf added on 2005-04-16 20:51:24:
Logged In: YES 
user_id=1260469

Define "start again."  You want to close/abandon this
report, and then I resubmit?

dgp added on 2005-04-16 11:35:01:
Logged In: YES 
user_id=80530

what a shame you weren't
logged in when you posted
the original report.  Then
you could have attached the file.

Want to start again?

m_schrumpf added on 2005-04-16 10:52:56:
Logged In: YES 
user_id=1260469

(Sorry about the first, poorly-formatted pasted-in patch. 
That's what happens when you move a text file from Windows
to Unix without checking the EOL characters.)

nobody added on 2005-04-16 10:45:11:
Logged In: NO 

--- tkConsole.cMon Aug 05 00:30:38 2002
+++ tkConsole.cFri Apr 15 16:14:25 2005
@@ -12,6 +12,9 @@
  *
  * RCS: @(#) $Id: tkConsole.c,v 1.18 2002/08/05 04:30:38
dgp Exp $
  */
+ 
+#include "tclPort.h"
+#include "tclIO.h"
 
 #include "tk.h"
 #include <string.h>
@@ -115,6 +118,8 @@
     int mode;
     char *bufMode;
     HANDLE handle;
+Tcl_Channel chan;
+ChannelState *statePtr;
 
     switch (type) {
 case TCL_STDIN:
@@ -186,9 +191,24 @@
 }
     } else if (fileType == FILE_TYPE_UNKNOWN) {
 return 1;
-    } else if (Tcl_GetStdChannel(type) == NULL) {
+} else if ((chan = Tcl_GetStdChannel(type)) == NULL) {
 return 1;
     }
+/*
+ * Tcl_GetStdChannel is only called if wish.exe was started
+ * from a parent process that grabs pipes to stdio channels
+ * (i.e. using CreateProcess() with inheritable pipes assigned
+ * to the child's stdio).
+ * A succesful call to Tcl_GetStdChannel increments refCount,
+ * which leaves the total count at 2 when calling
+ * CheckForStdChannelsBeingClosed(), preventing wish.exe from
+ * actually closing the IO handles when [close] is called on
+ * the last instance of a channel.
+ * Since the parent process is probably expecting these to be
+ * closed when wish.exe calls [close], decrement the count
here.
+ */
+statePtr = ((Channel *) (chan))->state;
+statePtr->refCount--;
 
     return 0;
 }
@@ -197,7 +217,7 @@
  * Mac should always use a console channel, Unix should if
it's trying to
  */
 
-#define ShouldUseConsoleChannel(chan) (1)
+#define ShouldUseConsoleChannel(type) (1)
 #endif
 

 /*

nobody added on 2005-04-16 10:43:29:
Logged In: NO 

Patch file attachment didn't upload:

--- tkConsole.cMon Aug 05 00:30:38 2002

+++ tkConsole.cFri Apr 15 16:14:25 2005

@@ -12,6 +12,9 @@

  *

  * RCS: @(#) $Id: tkConsole.c,v 1.18 2002/08/05 04:30:38
dgp Exp $

  */

+ 

+#include "tclPort.h"

+#include "tclIO.h"

 

 #include "tk.h"

 #include <string.h>

@@ -115,6 +118,8 @@

     int mode;

     char *bufMode;

     HANDLE handle;

+Tcl_Channel chan;

+ChannelState *statePtr;

 

     switch (type) {

 case TCL_STDIN:

@@ -186,9 +191,24 @@

 }

     } else if (fileType == FILE_TYPE_UNKNOWN) {

 return 1;

-    } else if (Tcl_GetStdChannel(type) == NULL) {

+} else if ((chan = Tcl_GetStdChannel(type)) == NULL) {

 return 1;

     }

+/*

+ * Tcl_GetStdChannel is only called if wish.exe was started

+ * from a parent process that grabs pipes to stdio channels

+ * (i.e. using CreateProcess() with inheritable pipes assigned

+ * to the child's stdio).

+ * A succesful call to Tcl_GetStdChannel increments refCount,

+ * which leaves the total count at 2 when calling

+ * CheckForStdChannelsBeingClosed(), preventing wish.exe from

+ * actually closing the IO handles when [close] is called on

+ * the last instance of a channel.

+ * Since the parent process is probably expecting these to be

+ * closed when wish.exe calls [close], decrement the count
here.

+ */

+statePtr = ((Channel *) (chan))->state;

+statePtr->refCount--;

 

     return 0;

 }

@@ -197,7 +217,7 @@

  * Mac should always use a console channel, Unix should if
it's trying to

  */

 

-#define ShouldUseConsoleChannel(chan) (1)

+#define ShouldUseConsoleChannel(type) (1)

 #endif

 

 /*