From dd13549c2381c348b6536501d389e513a6082f5d Mon Sep 17 00:00:00 2001 From: andreas_kupries Date: Fri, 4 Apr 2008 16:45:48 +0000 Subject: * 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. --- ChangeLog | 10 ++++++++++ generic/tclIORChan.c | 16 +++++++++++++++- tests/ioCmd.test | 14 +++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d06fc1..774b44e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-04-04 Andreas Kupries + + * 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 * generic/tclIO.c (CopyData): Applied patch [Bug 1932639] to diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 94950e7..905a773 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.28.2.1 2008/04/04 16:45:50 andreas_kupries Exp $ */ #include @@ -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..024e622 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.36.2.1 2008/04/04 16:45:51 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 -- cgit v0.12