Index: ChangeLog =================================================================== diff -u -r09b69017b6e76294eb4553341a98e5409d4a5741 -r5fae57ab03ce52f7e2e5b3bc954eb6b97c3f33d1 --- ChangeLog (.../ChangeLog) (revision 09b69017b6e76294eb4553341a98e5409d4a5741) +++ ChangeLog (.../ChangeLog) (revision 5fae57ab03ce52f7e2e5b3bc954eb6b97c3f33d1) @@ -1,13 +1,17 @@ +2011-02-09 + * Backport of nsf to handle partial implicit deletes + 2011-01-20 * Change backport of fix below to a check of numEntries - + 2011-01-20 * Backport of fix for nsf : fixed a nasty bug within namespace deletion, when a deletion of one tcl cmd caused implicit deletions of other cmds in the same namespace. The classical idiom for looking over hash tables with Tcl_GetHashValue() and Tcl_NextHashEntry(hSrch) can lead to crashes (and has different - behavior depending on the number of buckets). + behavior depending on the number of buckets). This fix handles + complete implicit deletes. 2010-12-26 * Make cppcheck happy Index: generic/xotcl.c =================================================================== diff -u -r09b69017b6e76294eb4553341a98e5409d4a5741 -r5fae57ab03ce52f7e2e5b3bc954eb6b97c3f33d1 --- generic/xotcl.c (.../xotcl.c) (revision 09b69017b6e76294eb4553341a98e5409d4a5741) +++ generic/xotcl.c (.../xotcl.c) (revision 5fae57ab03ce52f7e2e5b3bc954eb6b97c3f33d1) @@ -1846,6 +1846,7 @@ for (hPtr = Tcl_FirstHashEntry(cmdTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd; + int expected; /* * If a destroy of one element of the hash table triggers the * destroy of another item, Tcl_NextHashEntry() can lead to a @@ -1859,6 +1860,7 @@ if (cmdTable->numEntries < 1) { break; } + expected = cmdTable->numEntries; cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); if (!Tcl_Command_cmdEpoch(cmd)) { char *oname = Tcl_GetHashKey(cmdTable, hPtr); @@ -1875,10 +1877,12 @@ /* in the exit handler physical destroy --> directly call destroy */ if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == XOTCL_EXITHANDLER_ON_PHYSICAL_DESTROY) { - if (XOTclObjectIsClass(obj)) + if (XOTclObjectIsClass(obj)) { PrimitiveCDestroy((ClientData) obj); - else + } else { PrimitiveODestroy((ClientData) obj); + } + expected --; } else { if (obj->teardown && obj->id && !(obj->flags & XOTCL_DESTROY_CALLED)) { @@ -1893,11 +1897,20 @@ } /*(void*) Tcl_DeleteCommandFromToken(interp, oid);*/ } + expected --; } } } DSTRING_FREE(&name); } + /* + * If the hash table numEntries differs from expected, a deletion + * of one entry must have triggered other deletions. So we refetch + * the hSrch structure. + */ + if (cmdTable->numEntries != expected) { + hPtr = Tcl_FirstHashEntry(cmdTable, &hSrch); + } } }