summaryrefslogtreecommitdiffstats
path: root/generic/tclVar.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2009-10-17 22:35:58 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2009-10-17 22:35:58 (GMT)
commit391cc5529b10b842b5e34acb19bf559b56df7f49 (patch)
tree3b20f9da036fc4ea0a45e81d762efb0f84c787bb /generic/tclVar.c
parent0d31e4cefc735abf4b5eb232c3b89effa9ebc3aa (diff)
downloadtcl-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/tclVar.c')
-rw-r--r--generic/tclVar.c30
1 files changed, 25 insertions, 5 deletions
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;
}
/*