summaryrefslogtreecommitdiffstats
path: root/generic/tclVar.c
diff options
context:
space:
mode:
authordkf <dkf@noemail.net>2009-10-17 22:35:57 (GMT)
committerdkf <dkf@noemail.net>2009-10-17 22:35:57 (GMT)
commitd2ff7e38aceaf1b35515ef8f18d2cda7d0034cbe (patch)
tree3b20f9da036fc4ea0a45e81d762efb0f84c787bb /generic/tclVar.c
parent9890bb03e7b798e74d77b195f1faa8c2e2cd4fea (diff)
downloadtcl-d2ff7e38aceaf1b35515ef8f18d2cda7d0034cbe.zip
tcl-d2ff7e38aceaf1b35515ef8f18d2cda7d0034cbe.tar.gz
tcl-d2ff7e38aceaf1b35515ef8f18d2cda7d0034cbe.tar.bz2
Fix [Bug 2629338]: Stop evil unset traces from accessing freed memory.
FossilOrigin-Name: 3164b694cde7cb01dafc6be7fd7ec8d764f61052
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;
}
/*