diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2009-10-17 22:35:58 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2009-10-17 22:35:58 (GMT) |
commit | 391cc5529b10b842b5e34acb19bf559b56df7f49 (patch) | |
tree | 3b20f9da036fc4ea0a45e81d762efb0f84c787bb /generic | |
parent | 0d31e4cefc735abf4b5eb232c3b89effa9ebc3aa (diff) | |
download | tcl-391cc5529b10b842b5e34acb19bf559b56df7f49.zip tcl-391cc5529b10b842b5e34acb19bf559b56df7f49.tar.gz tcl-391cc5529b10b842b5e34acb19bf559b56df7f49.tar.bz2 |
Fix [Bug 2629338]: Stop evil unset traces from accessing freed memory.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclTrace.c | 3 | ||||
-rw-r--r-- | generic/tclVar.c | 30 |
2 files changed, 27 insertions, 6 deletions
diff --git a/generic/tclTrace.c b/generic/tclTrace.c index bc6d289..346defc 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclTrace.c,v 1.47.2.1 2008/10/08 14:52:39 dgp Exp $ + * RCS: @(#) $Id: tclTrace.c,v 1.47.2.2 2009/10/17 22:35:58 dkf Exp $ */ #include "tclInt.h" @@ -2894,6 +2894,7 @@ Tcl_UntraceVar2( } else { prevPtr->nextPtr = nextPtr; } + tracePtr->nextPtr = NULL; Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); for (tracePtr = nextPtr; tracePtr != NULL; diff --git a/generic/tclVar.c b/generic/tclVar.c index 3a3a10f..969cc17 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -16,7 +16,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.160.2.5 2009/08/25 21:01:05 andreas_kupries Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.160.2.6 2009/10/17 22:35:58 dkf Exp $ */ #include "tclInt.h" @@ -2364,11 +2364,22 @@ UnsetVarStruct( if ((dummyVar.flags & VAR_TRACED_UNSET) || (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET))) { dummyVar.flags &= ~VAR_TRACE_ACTIVE; - TclObjCallVarTraces(iPtr, arrayPtr, (Var *) &dummyVar, - part1Ptr, part2Ptr, + TclObjCallVarTraces(iPtr, arrayPtr, &dummyVar, part1Ptr, part2Ptr, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0, -1); + + /* + * The traces that we just called may have triggered a change in + * the set of traces. [Bug 2629338] + */ + + tracePtr = NULL; + if (TclIsVarTraced(&dummyVar)) { + tPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) &dummyVar); + tracePtr = Tcl_GetHashValue(tPtr); + } + if (tPtr) { Tcl_DeleteHashEntry(tPtr); } @@ -2381,6 +2392,7 @@ UnsetVarStruct( VarTrace *prevPtr = tracePtr; tracePtr = tracePtr->nextPtr; + prevPtr->nextPtr = NULL; Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC); } for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; @@ -4382,7 +4394,7 @@ TclDeleteNamespaceVars( varPtr = VarHashFirstVar(tablePtr, &search)) { Tcl_Obj *objPtr = Tcl_NewObj(); Tcl_IncrRefCount(objPtr); - + VarHashRefCount(varPtr)++; /* Make sure we get to remove from * hash. */ Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr); @@ -4390,13 +4402,13 @@ TclDeleteNamespaceVars( NULL, flags); Tcl_DecrRefCount(objPtr); /* free no longer needed obj */ - /* * Remove the variable from the table and force it undefined in case * an unset trace brought it back from the dead. */ if (TclIsVarTraced(varPtr)) { + ActiveVarTrace *activePtr; Tcl_HashEntry *tPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr); VarTrace *tracePtr = (VarTrace *) Tcl_GetHashValue(tPtr); @@ -4405,10 +4417,17 @@ TclDeleteNamespaceVars( VarTrace *prevPtr = tracePtr; tracePtr = tracePtr->nextPtr; + prevPtr->nextPtr = NULL; Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC); } Tcl_DeleteHashEntry(tPtr); varPtr->flags &= ~VAR_ALL_TRACES; + for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; + activePtr = activePtr->nextPtr) { + if (activePtr->varPtr == varPtr) { + activePtr->nextTracePtr = NULL; + } + } } VarHashRefCount(varPtr)--; VarHashDeleteEntry(varPtr); @@ -4511,6 +4530,7 @@ TclDeleteCompiledLocalVars( UnsetVarStruct(varPtr, NULL, iPtr, *namePtrPtr, NULL, TCL_TRACE_UNSETS); } + framePtr->numCompiledLocals = 0; } /* |