summaryrefslogtreecommitdiffstats
path: root/generic/tclIORChan.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclIORChan.c')
-rw-r--r--generic/tclIORChan.c82
1 files changed, 42 insertions, 40 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index 5acd950..e8a243b 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -60,27 +60,27 @@ static int ReflectTruncate(void *clientData,
*/
static const Tcl_ChannelType tclRChannelType = {
- "tclrchannel", /* Type name. */
+ "tclrchannel", /* Type name. */
TCL_CHANNEL_VERSION_5, /* v5 channel */
- NULL, /* Close channel, clean instance data */
- ReflectInput, /* Handle read request */
- ReflectOutput, /* Handle write request */
+ NULL, /* Old close API */
+ ReflectInput, /* Handle read request */
+ ReflectOutput, /* Handle write request */
NULL,
- ReflectSetOption, /* Set options. NULL'able */
- ReflectGetOption, /* Get options. NULL'able */
- ReflectWatch, /* Initialize notifier */
- NULL, /* Get OS handle from the channel. NULL'able */
- ReflectClose, /* No close2 support. NULL'able */
- ReflectBlock, /* Set blocking/nonblocking. NULL'able */
- NULL, /* Flush channel. Not used by core. NULL'able */
- NULL, /* Handle events. NULL'able */
- ReflectSeekWide, /* Move access point (64 bit). NULL'able */
+ ReflectSetOption, /* Set options. */
+ ReflectGetOption, /* Get options. */
+ ReflectWatch, /* Initialize notifier */
+ NULL, /* Get OS handle from the channel. */
+ ReflectClose, /* Close channel. Clean instance data */
+ ReflectBlock, /* Set blocking/nonblocking. */
+ NULL, /* Flush channel. */
+ NULL, /* Handle events. */
+ ReflectSeekWide, /* Move access point (64 bit). */
#if TCL_THREADS
- ReflectThread, /* thread action, tracking owner */
+ ReflectThread, /* thread action, tracking owner */
#else
- NULL, /* thread action */
+ NULL, /* thread action */
#endif
- ReflectTruncate /* Truncate. NULL'able */
+ ReflectTruncate /* Truncate. */
};
/*
@@ -94,11 +94,10 @@ typedef struct {
* Tcl level part of the channel. NULL here
* signals the channel is dead because the
* interpreter/thread containing its Tcl
- * command is gone.
- */
+ * command is gone. */
#if TCL_THREADS
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. == Handler thread */
- Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */
+ Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */
#endif
Tcl_Obj *cmd; /* Callback command prefix */
Tcl_Obj *methods; /* Methods to append to command prefix */
@@ -255,7 +254,7 @@ typedef struct {
struct ForwardParamInput {
ForwardParamBase base; /* "Supertype". MUST COME FIRST. */
char *buf; /* O: Where to store the read bytes */
- Tcl_Size toRead; /* I: #bytes to read,
+ Tcl_Size toRead; /* I: #bytes to read,
* O: #bytes actually read */
};
struct ForwardParamOutput {
@@ -502,7 +501,7 @@ TclChanCreateObjCmd(
Tcl_Obj *cmdNameObj; /* Command name */
Tcl_Channel chan; /* Token for the new channel */
Tcl_Obj *modeObj; /* mode in obj form for method call */
- Tcl_Size listc; /* Result of 'initialize', and of */
+ Tcl_Size listc; /* Result of 'initialize', and of */
Tcl_Obj **listv; /* its sublist in the 2nd element */
int methIndex; /* Encoded method name */
int result; /* Result code for 'initialize' */
@@ -2262,23 +2261,37 @@ NextHandle(void)
return resObj;
}
-static void
-FreeReflectedChannel(
- void *blockPtr)
+static inline void
+CleanRefChannelInstance(
+ ReflectedChannel *rcPtr)
{
- ReflectedChannel *rcPtr = (ReflectedChannel *) blockPtr;
- Channel *chanPtr = (Channel *) rcPtr->chan;
-
- TclChannelRelease((Tcl_Channel)chanPtr);
if (rcPtr->name) {
+ /*
+ * Reset obj-type (channel is deleted or dead anyway) to avoid leakage
+ * by cyclic references (see bug [79474c58800cdf94]).
+ */
+ TclFreeInternalRep(rcPtr->name);
Tcl_DecrRefCount(rcPtr->name);
+ rcPtr->name = NULL;
}
if (rcPtr->methods) {
Tcl_DecrRefCount(rcPtr->methods);
+ rcPtr->methods = NULL;
}
if (rcPtr->cmd) {
Tcl_DecrRefCount(rcPtr->cmd);
+ rcPtr->cmd = NULL;
}
+}
+static void
+FreeReflectedChannel(
+ void *blockPtr)
+{
+ ReflectedChannel *rcPtr = (ReflectedChannel *) blockPtr;
+ Channel *chanPtr = (Channel *) rcPtr->chan;
+
+ TclChannelRelease((Tcl_Channel)chanPtr);
+ CleanRefChannelInstance(rcPtr);
Tcl_Free(rcPtr);
}
@@ -2548,18 +2561,7 @@ MarkDead(
if (rcPtr->dead) {
return;
}
- if (rcPtr->name) {
- Tcl_DecrRefCount(rcPtr->name);
- rcPtr->name = NULL;
- }
- if (rcPtr->methods) {
- Tcl_DecrRefCount(rcPtr->methods);
- rcPtr->methods = NULL;
- }
- if (rcPtr->cmd) {
- Tcl_DecrRefCount(rcPtr->cmd);
- rcPtr->cmd = NULL;
- }
+ CleanRefChannelInstance(rcPtr);
rcPtr->dead = 1;
}