summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--generic/tclIORChan.c16
-rw-r--r--tests/ioCmd.test14
3 files changed, 38 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 5f8922d..6031f9e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-04-04 Andreas Kupries <andreask@activestate.com>
+
+ * generic/tclIORChan.c (ReflectClose): Added missing removal of
+ the now closed channel from the reflection map. Before we could
+ crash the system by invoking 'chan postevent' on a closed
+ reflected channel, dereferencing the dangling pointer in the
+ map.
+
+ * tests/ioCmd.test (iocmd-31.8): Testcase for the above.
+
2008-04-03 Andreas Kupries <andreask@activestate.com>
* generic/tclIO.c (CopyData): Applied patch [Bug 1932639] to
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index 94950e7..10d0b2e 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -15,7 +15,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIORChan.c,v 1.28 2008/02/26 21:50:52 jenglish Exp $
+ * RCS: @(#) $Id: tclIORChan.c,v 1.29 2008/04/04 16:46:57 andreas_kupries Exp $
*/
#include <tclInt.h>
@@ -1010,6 +1010,8 @@ ReflectClose(
ReflectedChannel *rcPtr = (ReflectedChannel *) clientData;
int result; /* Result code for 'close' */
Tcl_Obj *resObj; /* Result data for 'close' */
+ ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */
+ Tcl_HashEntry* hPtr; /* Entry in the above map */
if (interp == NULL) {
/*
@@ -1090,6 +1092,18 @@ ReflectClose(
Tcl_DecrRefCount(resObj); /* Remove reference we held from the
* invoke */
+
+ /*
+ * Remove the channel from the map before releasing the memory, to
+ * prevent future accesses (like by 'postevent') from finding and
+ * dereferencing a dangling pointer.
+ */
+
+ rcmPtr = GetReflectedChannelMap (interp);
+ hPtr = Tcl_FindHashEntry (&rcmPtr->map,
+ Tcl_GetChannelName (rcPtr->chan));
+ Tcl_DeleteHashEntry (hPtr);
+
FreeReflectedChannel(rcPtr);
#ifdef TCL_THREADS
}
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index 2b4877f..fcb0b74 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -13,7 +13,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: ioCmd.test,v 1.36 2008/03/11 22:28:34 das Exp $
+# RCS: @(#) $Id: ioCmd.test,v 1.37 2008/04/04 16:46:57 andreas_kupries Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest 2
@@ -1795,6 +1795,18 @@ test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body {
rename foo {}
set res
} -result {{watch rc* write} {} TOCK {} {watch rc* {}}}
+test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
+ proc foo {args} {oninit; onfinal; track; return}
+ proc dummy args { return }
+ set c [chan create {r w} foo]
+ fileevent $c readable dummy
+} -body {
+ close $c
+ chan postevent $c read
+} -cleanup {
+ rename foo {}
+ rename dummy {}
+} -returnCodes error -result {can not find reflected channel named "rc*"}
# ### ### ### ######### ######### #########
## Same tests as above, but exercising the code forwarding and