diff options
author | dgp <dgp@users.sourceforge.net> | 2017-12-04 18:36:14 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2017-12-04 18:36:14 (GMT) |
commit | 92f8ce13dfb1299030dc844252d7478caaaa7687 (patch) | |
tree | 35b94b3f35634f2300cfaec0a988a33856890f0b | |
parent | e68b4918069d622ccc7f9f6f98e8432df3f3baad (diff) | |
download | tcl-92f8ce13dfb1299030dc844252d7478caaaa7687.zip tcl-92f8ce13dfb1299030dc844252d7478caaaa7687.tar.gz tcl-92f8ce13dfb1299030dc844252d7478caaaa7687.tar.bz2 |
[4f6a1ebd64] Different fix for the problem. Re-order the filling of the
subcommand table so there is no longer a conflict where multiple intreps of
a single value are sought. If the mapDict and exportList are the same,
then each key in the mapDict is known to be an element of the exportList
without needing to check.
-rw-r--r-- | generic/tclNamesp.c | 115 | ||||
-rw-r--r-- | tests/namespace.test | 19 |
2 files changed, 73 insertions, 61 deletions
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 4b72e03..18cd07c 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -6582,6 +6582,8 @@ BuildEnsembleConfig( int i, j, isNew; Tcl_HashTable *hash = &ensemblePtr->subcommandTable; Tcl_HashEntry *hPtr; + Tcl_Obj *mapDict = ensemblePtr->subcommandDict; + Tcl_Obj *exportList = ensemblePtr->subcmdList; if (hash->numEntries != 0) { /* @@ -6601,51 +6603,67 @@ BuildEnsembleConfig( Tcl_InitHashTable(hash, TCL_STRING_KEYS); } - /* - * See if we've got an export list. If so, we will only export exactly - * those commands, which may be either implemented by the prefix in the - * subcommandDict or mapped directly onto the namespace's commands. - */ - - if (ensemblePtr->subcmdList != NULL) { - Tcl_Obj **subcmdv, *target, *cmdObj, *cmdPrefixObj; - int subcmdc; + if (mapDict) { + /* + * We have a mapping dictionary to direct filling of the subcommand + * table. Every key, value in the dict should go into the table + * unless we have an export list that holds some of the keys back. + */ - TclListObjGetElements(NULL, ensemblePtr->subcmdList, &subcmdc, - &subcmdv); - for (i=0 ; i<subcmdc ; i++) { - char *name = TclGetString(subcmdv[i]); + Tcl_DictSearch dictSearch; + Tcl_Obj *keyObj, *valueObj; + int done; - hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + Tcl_DictObjFirst(NULL, mapDict, &dictSearch, &keyObj, &valueObj, &done); + while (!done) { + int nameLen, insert = 1; + char *name = TclGetStringFromObj(keyObj, &nameLen); + + if (exportList && (exportList != mapDict)) { + Tcl_Obj **subv; + int subc; + + insert = 0; + TclListObjGetElements(NULL, exportList, &subc, &subv); + for (i = 0; i < subc; i++) { + int compareLen; + const char *compare + = TclGetStringFromObj(subv[i], &compareLen); + + if ((nameLen == compareLen) + && (memcmp(name, compare, (size_t)nameLen) == 0)) { + insert = 1; + break; + } + } + } + if (insert) { + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + Tcl_SetHashValue(hPtr, valueObj); + Tcl_IncrRefCount(valueObj); + } + Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done); + } + } + if (exportList) { + /* + * We have an export list. Put into the table each element that's + * not already there. + */ + int subc; + Tcl_Obj **subv, *cmdObj, *cmdPrefixObj; - /* - * Skip non-unique cases. - */ + TclListObjGetElements(NULL, exportList, &subc, &subv); + for (i=0 ; i<subc ; i++) { + char *name = TclGetString(subv[i]); + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); if (!isNew) { + /* Subcommand already in the table, from the mapDict. */ continue; } - /* - * Look in our dictionary (if present) for the command. - */ - - if (ensemblePtr->subcommandDict != NULL) { - Tcl_DictObjGet(NULL, ensemblePtr->subcommandDict, subcmdv[i], - &target); - if (target != NULL) { - Tcl_SetHashValue(hPtr, target); - Tcl_IncrRefCount(target); - continue; - } - } - - /* - * Not there, so map onto the namespace. Note in this case that we - * do not guarantee that the command is actually there; that is - * the programmer's responsibility (or [::unknown] of course). - */ - + /* Need to put entry in table, but it's not in mapDict */ cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); if (ensemblePtr->nsPtr->parentPtr != NULL) { Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); @@ -6656,28 +6674,7 @@ BuildEnsembleConfig( Tcl_SetHashValue(hPtr, cmdPrefixObj); Tcl_IncrRefCount(cmdPrefixObj); } - } else if (ensemblePtr->subcommandDict != NULL) { - /* - * No subcmd list, but we do have a mapping dictionary so we should - * use the keys of that. Convert the dictionary's contents into the - * form required for the ensemble's internal hashtable. - */ - - Tcl_DictSearch dictSearch; - Tcl_Obj *keyObj, *valueObj; - int done; - - Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch, - &keyObj, &valueObj, &done); - while (!done) { - char *name = TclGetString(keyObj); - - hPtr = Tcl_CreateHashEntry(hash, name, &isNew); - Tcl_SetHashValue(hPtr, valueObj); - Tcl_IncrRefCount(valueObj); - Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done); - } - } else { + } else if (mapDict == NULL) { /* * Discover what commands are actually exported by the namespace. * What we have is an array of patterns and a hash table whose keys diff --git a/tests/namespace.test b/tests/namespace.test index 7d41258..0ad8451 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -1599,14 +1599,29 @@ test namespace-42.9 { deallocated List struct. } -setup { namespace eval n {namespace ensemble create} - dict set list one ::two - namespace ensemble configure n -subcommands $list -map $list + set lst [dict create one ::two] + namespace ensemble configure n -subcommands $lst -map $lst } -body { n one } -cleanup { namespace delete n + unset -nocomplain lst } -returnCodes error -match glob -result {invalid command name*} +test namespace-42.10 { + ensembles: [Bug 4f6a1ebd64] segmentation fault due to pointer to a + deallocated List struct (this time with duplicate of one in "dict"). +} -setup { + namespace eval n {namespace ensemble create} + set lst [list one ::two one ::three] + namespace ensemble configure n -subcommands $lst -map $lst +} -body { + n one +} -cleanup { + namespace delete n + unset -nocomplain lst +} -returnCodes error -match glob -result {invalid command name *three*} + test namespace-43.1 {ensembles: dict-driven} { namespace eval ns { namespace export x* |