summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2024-05-16 20:28:04 (GMT)
committersebres <sebres@users.sourceforge.net>2024-05-16 20:28:04 (GMT)
commita7ec3ac2ad4ef2890f4229c9d9b3c079e94d188b (patch)
tree758ef95e5f6585f4cb5143a745f4751e8b515152
parentdfa67061deda621491e1623f06e61b93da516195 (diff)
downloadtcl-a7ec3ac2ad4ef2890f4229c9d9b3c079e94d188b.zip
tcl-a7ec3ac2ad4ef2890f4229c9d9b3c079e94d188b.tar.gz
tcl-a7ec3ac2ad4ef2890f4229c9d9b3c079e94d188b.tar.bz2
fix mem-leak originating by cyclic reference `rcPtr->name (type "channel", its refCount may be larger than 1) => statPtr => chanPtr => chanPtr->instanceData => refChan`:
this would avoid that object rcPtr->name (name of channel that gets deleted or dead) still holds the reference to statPtr, see 2nd part of bug [79474c58800cdf94].
-rw-r--r--generic/tclIORChan.c41
-rw-r--r--tests/ioCmd.test2
2 files changed, 23 insertions, 20 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index 727239b..f2bb186 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -2211,23 +2211,37 @@ NextHandle(void)
return resObj;
}
-static void
-FreeReflectedChannel(
- char *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]).
+ */
+ TclFreeIntRep(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(
+ char *blockPtr)
+{
+ ReflectedChannel *rcPtr = (ReflectedChannel *) blockPtr;
+ Channel *chanPtr = (Channel *) rcPtr->chan;
+
+ TclChannelRelease((Tcl_Channel)chanPtr);
+ CleanRefChannelInstance(rcPtr);
ckfree(rcPtr);
}
@@ -2497,18 +2511,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;
}
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index b341aa8..3dbb3cc 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -2177,7 +2177,7 @@ test iocmd-32.3 {prevent copy-state against segfault by finalize, bug [79474c588
catch {close $ch}
}
if {$toev ne ""} { after cancel $toev }
- unset -nocomplain ::done ::ret ch in1 in2 in3 out1 out2 out3 toev
+ unset -nocomplain ::done ::ret ch in1 in2 in3 out1 out2 out3 toev clchlst
} -result {initialize read write finalize done}
# ### ### ### ######### ######### #########