diff options
author | dgp <dgp@users.sourceforge.net> | 2007-05-07 19:45:32 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2007-05-07 19:45:32 (GMT) |
commit | da6c10f827c3825c5cdd1f0f8d1af2acba0a0ef3 (patch) | |
tree | 29ed64b0e7e0caaaf8f2c0f26ced6a0aaa35d4fa /generic/tclVar.c | |
parent | 95748a33387880fba794dc3e9db352a218b1f84e (diff) | |
download | tcl-da6c10f827c3825c5cdd1f0f8d1af2acba0a0ef3.zip tcl-da6c10f827c3825c5cdd1f0f8d1af2acba0a0ef3.tar.gz tcl-da6c10f827c3825c5cdd1f0f8d1af2acba0a0ef3.tar.bz2 |
[Tcl Bug 1706140]
* generic/tclLink.c (LinkTraceProc): Update Tcl_VarTraceProcs so that
* generic/tclNamesp.c (Error*Read): they call Tcl_InterpDeleted()
* generic/tclTrace.c (Trace*Proc): for themselves, and do not rely
* generic/tclUtil.c (TclPrecTraceProc): on (frequently buggy) setting
of the TCL_INTERP_DESTROYED flag by the trace core.
* generic/tclVar.c: Update callers of TclCallVarTraces to not
pass in the TCL_INTERP_DESTROYED flag. Also apply filters so that
public routines only pass documented flag values down to lower level
routines.
* generic/tclTrace.c (TclCallVarTraces): The setting of the
TCL_INTERP_DESTROYED flag is now done entirely within the
TclCallVarTraces routine, the only place it can be done right.
Diffstat (limited to 'generic/tclVar.c')
-rw-r--r-- | generic/tclVar.c | 72 |
1 files changed, 24 insertions, 48 deletions
diff --git a/generic/tclVar.c b/generic/tclVar.c index 2e5f39d..dc76825 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.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: tclVar.c,v 1.133 2007/05/02 00:31:22 msofer Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.134 2007/05/07 19:45:34 dgp Exp $ */ #include "tclInt.h" @@ -1097,15 +1097,10 @@ Tcl_GetVar2Ex( { Var *varPtr, *arrayPtr; - /* - * We need a special flag check to see if we want to create part 1, - * because commands like lappend require read traces to trigger for - * previously non-existent values. - */ - + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclLookupVar(interp, part1, part2, flags, "read", - /*createPart1*/ (flags & TCL_TRACE_READS), - /*createPart2*/ 1, &arrayPtr); + /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } @@ -1155,15 +1150,10 @@ Tcl_ObjGetVar2( part1 = TclGetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : TclGetString(part2Ptr)); - /* - * We need a special flag check to see if we want to create part 1, - * because commands like lappend require read traces to trigger for - * previously non-existent values. - */ - + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read", - /*createPart1*/ (flags & TCL_TRACE_READS), - /*createPart2*/ 1, &arrayPtr); + /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } @@ -1453,6 +1443,9 @@ Tcl_SetVar2Ex( { Var *varPtr, *arrayPtr; + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG + |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclLookupVar(interp, part1, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { @@ -1512,6 +1505,9 @@ Tcl_ObjSetVar2( part1 = TclGetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : TclGetString(part2Ptr)); + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG + |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { @@ -1603,7 +1599,8 @@ TclPtrSetVar( /* * Invoke any read traces that have been set for the variable if it is - * requested; this is only done in the core when lappending. + * requested; this is only done in the core by the INST_LAPPEND_* + * instructions. */ if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL) @@ -1936,6 +1933,8 @@ Tcl_UnsetVar2( part1Ptr = Tcl_NewStringObj(part1, -1); Tcl_IncrRefCount(part1Ptr); + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); result = TclObjUnsetVar2(interp, part1Ptr, part2, flags); TclDecrRefCount(part1Ptr); @@ -2121,8 +2120,8 @@ UnsetVarStruct( if ((dummyVar.tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { dummyVar.flags &= ~VAR_TRACE_ACTIVE; - TclCallVarTraces(iPtr, arrayPtr, &dummyVar, part1, part2, - (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_INTERP_DESTROYED)) + TclCallVarTraces(iPtr, arrayPtr, &dummyVar, part1, part2, (flags + & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0); while (dummyVar.tracePtr != NULL) { VarTrace *tracePtr = dummyVar.tracePtr; @@ -2146,21 +2145,8 @@ UnsetVarStruct( dummyVarPtr = &dummyVar; if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) { - /* - * Deleting the elements of the array may cause traces to be fired on - * those elements. Before deleting them, bump the reference count of - * the array, so that if those trace procs make a global or upvar link - * to the array, the array is not deleted when the call stack gets - * popped (we will delete the array ourselves later in this function). - * - * Bumping the count can lead to the odd situation that elements of - * the array are being deleted when the array still exists, but since - * the array is about to be removed anyway, that shouldn't really - * matter. - */ - - DeleteArray(iPtr, part1, dummyVarPtr, - (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) + DeleteArray(iPtr, part1, dummyVarPtr, (flags + & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS); /* @@ -2390,10 +2376,7 @@ Tcl_LappendObjCmd( createdNewObj = 0; /* - * Use the TCL_TRACE_READS flag to ensure that if we have an array - * with no elements set yet, but with a read trace on it, we will - * create the variable and get read traces triggered. Note that you - * have to protect the variable pointers around the TclPtrGetVar call + * Protect the variable pointers around the TclPtrGetVar call * to insure that they remain valid even if the variable was undefined * and unused. */ @@ -2409,7 +2392,7 @@ Tcl_LappendObjCmd( } part1 = TclGetString(objv[1]); varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, NULL, - (TCL_TRACE_READS | TCL_LEAVE_ERR_MSG)); + TCL_LEAVE_ERR_MSG); varPtr->refCount--; if (arrayPtr != NULL) { arrayPtr->refCount--; @@ -4078,9 +4061,6 @@ TclDeleteNamespaceVars( } else if (nsPtr == (Namespace *) Tcl_GetCurrentNamespace(interp)) { flags = TCL_NAMESPACE_ONLY; } - if (Tcl_InterpDeleted(interp)) { - flags |= TCL_INTERP_DESTROYED; - } for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_FirstHashEntry(tablePtr, &search)) { @@ -4158,9 +4138,6 @@ TclDeleteVars( } else if (tablePtr == &currNsPtr->varTable) { flags |= TCL_NAMESPACE_ONLY; } - if (Tcl_InterpDeleted(interp)) { - flags |= TCL_INTERP_DESTROYED; - } for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { @@ -4389,8 +4366,7 @@ DeleteArray( Var *varPtr, /* Pointer to variable structure. */ int flags) /* Flags to pass to TclCallVarTraces: * TCL_TRACE_UNSETS and sometimes - * TCL_INTERP_DESTROYED, TCL_NAMESPACE_ONLY, - * or TCL_GLOBAL_ONLY. */ + * TCL_NAMESPACE_ONLY or TCL_GLOBAL_ONLY. */ { Tcl_HashSearch search; register Tcl_HashEntry *hPtr; |