summaryrefslogtreecommitdiffstats
path: root/generic/tclVar.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2016-09-07 17:30:18 (GMT)
committerdgp <dgp@users.sourceforge.net>2016-09-07 17:30:18 (GMT)
commitf4881ad277e61ae34673ee464a4d43ac5da32ab3 (patch)
tree4a866ebaa14a3878cab0cd22e0c654882add6131 /generic/tclVar.c
parent05c0da6eee9a84deb417980eb524efd8395516ec (diff)
parenta05766d3d315e7ecba48b10b3d24d98a7cd450df (diff)
downloadtcl-f4881ad277e61ae34673ee464a4d43ac5da32ab3.zip
tcl-f4881ad277e61ae34673ee464a4d43ac5da32ab3.tar.gz
tcl-f4881ad277e61ae34673ee464a4d43ac5da32ab3.tar.bz2
[4dbdd9af14] Plug mem leak when var unset trace re-creates namespace var.
Thanks mr_calvin for report and fix.
Diffstat (limited to 'generic/tclVar.c')
-rw-r--r--generic/tclVar.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/generic/tclVar.c b/generic/tclVar.c
index bdc64b7..e95307e 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -4498,11 +4498,14 @@ TclDeleteNamespaceVars(
Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr);
UnsetVarStruct(varPtr, NULL, iPtr, /* part1 */ objPtr,
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.
+ * We just unset the variable. However, an unset trace might
+ * have re-set it, or might have re-established traces on it.
+ * This namespace and its vartable are going away unconditionally,
+ * so we cannot let such things linger. That would be a leak.
+ *
+ * First we destroy all traces. ...
*/
if (TclIsVarTraced(varPtr)) {
@@ -4527,6 +4530,17 @@ TclDeleteNamespaceVars(
}
}
}
+
+ /*
+ * ...and then, if the variable still holds a value, we unset it
+ * again. This time with no traces left, we're sure it goes away.
+ */
+
+ if (!TclIsVarUndefined(varPtr)) {
+ UnsetVarStruct(varPtr, NULL, iPtr, /* part1 */ objPtr,
+ NULL, flags);
+ }
+ Tcl_DecrRefCount(objPtr); /* free no longer needed obj */
VarHashRefCount(varPtr)--;
VarHashDeleteEntry(varPtr);
}