From ac3259b669c253852e4108c8da44a959fb1465a9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 17 Nov 2017 08:32:16 +0000 Subject: Suggested patch for [4f51e1c5dc]: patch to correct linker flag sequence. Same change done for a few other platforms where it might matter. --- unix/configure | 8 ++++---- unix/tcl.m4 | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/unix/configure b/unix/configure index 39076a4..888fe0c 100755 --- a/unix/configure +++ b/unix/configure @@ -6954,7 +6954,7 @@ echo "$as_me: error: CYGWIN compile is only supported with --enable-threads" >&2 LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-lroot" echo "$as_me:$LINENO: checking for inet_ntoa in -lnetwork" >&5 @@ -7383,7 +7383,7 @@ fi # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" @@ -7525,7 +7525,7 @@ fi SHLIB_CFLAGS="-fpic" ;; esac - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7554,7 +7554,7 @@ fi NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 8a802fb..6ca2047 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -1258,7 +1258,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-lroot" AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) @@ -1402,7 +1402,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" @@ -1473,7 +1473,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ SHLIB_CFLAGS="-fpic" ;; esac - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1496,7 +1496,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" -- cgit v0.12 From e68b4918069d622ccc7f9f6f98e8432df3f3baad Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 29 Nov 2017 13:59:42 +0000 Subject: Cherry-picked test-cases from [046a5af026]: fix for issue [4f6a1ebd64]: ensemble: segmentation fault when -subcommand and -map values are the same object. --- tests/namespace.test | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/namespace.test b/tests/namespace.test index 71b6860..7d41258 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -1576,7 +1576,10 @@ test namespace-42.7 {ensembles: nested} { namespace delete ns set result } {{1 ::ns::x0::z} 1 2 3} -test namespace-42.8 {ensembles: [Bug 1670091]} -setup { +test namespace-42.8 { + ensembles: [Bug 1670091], panic due to pointer to a deallocated List + struct. +} -setup { proc demo args {} variable target [list [namespace which demo] x] proc trial args {variable target; string length $target} @@ -1591,6 +1594,19 @@ test namespace-42.8 {ensembles: [Bug 1670091]} -setup { rename foo {} } -result {} +test namespace-42.9 { + ensembles: [Bug 4f6a1ebd64], segmentation fault due to pointer to a + deallocated List struct. +} -setup { + namespace eval n {namespace ensemble create} + dict set list one ::two + namespace ensemble configure n -subcommands $list -map $list +} -body { + n one +} -cleanup { + namespace delete n +} -returnCodes error -match glob -result {invalid command name*} + test namespace-43.1 {ensembles: dict-driven} { namespace eval ns { namespace export x* -- cgit v0.12 From 1a237e67df1f72fce66636d7efcd7cffa82bd0b8 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 1 Dec 2017 10:38:04 +0000 Subject: Simpler solution for Itcl 3.4 build (compatibilty) problem. Thanks to Don Porter for bringing this to my attention! --- generic/tclIntDecls.h | 67 ++++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 51 deletions(-) diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index c3ee084..5848bb3 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -28,6 +28,22 @@ # endif #endif +#if !defined(TCL_NO_DEPRECATED) && (TCL_MAJOR_VERSION < 9) +/* Those macro's are especially for Itcl 3.4 compatibility */ +# define tclCreateNamespace tcl_CreateNamespace +# define tclDeleteNamespace tcl_DeleteNamespace +# define tclAppendExportList tcl_AppendExportList +# define tclExport tcl_Export +# define tclImport tcl_Import +# define tclForgetImport tcl_ForgetImport +# define tclGetCurrentNamespace_ tcl_GetCurrentNamespace +# define tclGetGlobalNamespace_ tcl_GetGlobalNamespace +# define tclFindNamespace tcl_FindNamespace +# define tclFindCommand tcl_FindCommand +# define tclGetCommandFromObj tcl_GetCommandFromObj +# define tclGetCommandFullName tcl_GetCommandFullName +#endif /* !defined(TCL_NO_DEPRECATED) */ + /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made @@ -1367,57 +1383,6 @@ extern const TclIntStubs *tclIntStubsPtr; # undef TclGetCommandFullName # undef TclCopyChannelOld # undef TclSockMinimumBuffersOld - -#if !defined(TCL_NO_DEPRECATED) -# undef Tcl_CreateNamespace -# define Tcl_CreateNamespace \ - (tclIntStubsPtr->tclCreateNamespace) /* 113 */ -# define tcl_CreateNamespace tclCreateNamespace -# undef Tcl_DeleteNamespace -# define Tcl_DeleteNamespace \ - (tclIntStubsPtr->tclDeleteNamespace) /* 114 */ -# define tcl_DeleteNamespace tclDeleteNamespace -# undef Tcl_AppendExportList -# define Tcl_AppendExportList \ - (tclIntStubsPtr->tclAppendExportList) /* 112 */ -# define tcl_AppendExportList tclAppendExportList -# undef Tcl_Export -# define Tcl_Export \ - (tclIntStubsPtr->tclExport) /* 115 */ -# define tcl_Export tclExport -# undef Tcl_Import -# define Tcl_Import \ - (tclIntStubsPtr->tclImport) /* 127 */ -# define tcl_Import tclImport -# undef Tcl_ForgetImport -# define Tcl_ForgetImport \ - (tclIntStubsPtr->tclForgetImport) /* 121 */ -# define tcl_ForgetImport tclForgetImport -# undef Tcl_GetCurrentNamespace -# define Tcl_GetCurrentNamespace \ - (tclIntStubsPtr->tclGetCurrentNamespace_) /* 124 */ -# define tcl_GetCurrentNamespace tclGetCurrentNamespace_ -# undef Tcl_GetGlobalNamespace -# define Tcl_GetGlobalNamespace \ - (tclIntStubsPtr->tclGetGlobalNamespace_) /* 125 */ -# define tcl_GetGlobalNamespace tclGetGlobalNamespace_ -# undef Tcl_FindNamespace -# define Tcl_FindNamespace \ - (tclIntStubsPtr->tclFindNamespace) /* 117 */ -# define tcl_FindNamespace tclFindNamespace -# undef Tcl_FindCommand -# define Tcl_FindCommand \ - (tclIntStubsPtr->tclFindCommand) /* 116 */ -# define tcl_FindCommand tclFindCommand -# undef Tcl_GetCommandFromObj -# define Tcl_GetCommandFromObj \ - (tclIntStubsPtr->tclGetCommandFromObj) /* 122 */ -# define tcl_GetCommandFromObj tclGetCommandFromObj -# undef Tcl_GetCommandFullName -# define Tcl_GetCommandFullName \ - (tclIntStubsPtr->tclGetCommandFullName) /* 123 */ -# define tcl_GetCommandFullName tclGetCommandFullName -#endif /* !defined(TCL_NO_DEPRECATED) */ #endif #endif /* _TCLINTDECLS */ -- cgit v0.12 From 92f8ce13dfb1299030dc844252d7478caaaa7687 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 4 Dec 2017 18:36:14 +0000 Subject: [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. --- generic/tclNamesp.c | 115 +++++++++++++++++++++++++-------------------------- 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 ; isubcommandDict != 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* -- cgit v0.12 From 8a44c35e8c34860fe2ea418899c8f62fc25e06bb Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 5 Dec 2017 14:36:33 +0000 Subject: Another revised fix, much closer to sebres' patch now. --- generic/tclNamesp.c | 152 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 62 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 18cd07c..1556ec9 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -6583,7 +6583,7 @@ BuildEnsembleConfig( Tcl_HashTable *hash = &ensemblePtr->subcommandTable; Tcl_HashEntry *hPtr; Tcl_Obj *mapDict = ensemblePtr->subcommandDict; - Tcl_Obj *exportList = ensemblePtr->subcmdList; + Tcl_Obj *subList = ensemblePtr->subcmdList; if (hash->numEntries != 0) { /* @@ -6603,78 +6603,106 @@ BuildEnsembleConfig( Tcl_InitHashTable(hash, TCL_STRING_KEYS); } - if (mapDict) { + if (subList) { + int subc; + Tcl_Obj **subv, *target, *cmdObj, *cmdPrefixObj; + char *name; + /* - * 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. + * There is a list of exactly what subcommands go in the table. + * Must determine the target for each. */ - Tcl_DictSearch dictSearch; - Tcl_Obj *keyObj, *valueObj; - int done; - - 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; - } + Tcl_ListObjGetElements(NULL, subList, &subc, &subv); + if (subList == mapDict) { + /* + * Strange case where explicit list of subcommands is same value + * as the dict mapping to targets. + */ + + for (i = 0; i < subc; i += 2) { + name = TclGetString(subv[i]); + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + if (!isNew) { + cmdObj = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + Tcl_DecrRefCount(cmdObj); } - } - if (insert) { + Tcl_SetHashValue(hPtr, subv[i+1]); + Tcl_IncrRefCount(subv[i+1]); + + name = TclGetString(subv[i+1]); hPtr = Tcl_CreateHashEntry(hash, name, &isNew); - Tcl_SetHashValue(hPtr, valueObj); - Tcl_IncrRefCount(valueObj); + if (isNew) { + cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); + if (ensemblePtr->nsPtr->parentPtr != NULL) { + Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); + } else { + Tcl_AppendStringsToObj(cmdObj, name, NULL); + } + cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); + Tcl_SetHashValue(hPtr, cmdPrefixObj); + Tcl_IncrRefCount(cmdPrefixObj); + } } - 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; + } else { + /* Usual case where we can freely act on the list and dict. */ - TclListObjGetElements(NULL, exportList, &subc, &subv); - for (i=0 ; insPtr->fullName, -1); - if (ensemblePtr->nsPtr->parentPtr != NULL) { - Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); - } else { - Tcl_AppendStringsToObj(cmdObj, name, NULL); + /* + * target was not in the dictionary 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). + */ + cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); + if (ensemblePtr->nsPtr->parentPtr != NULL) { + Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); + } else { + Tcl_AppendStringsToObj(cmdObj, name, NULL); + } + cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); + Tcl_SetHashValue(hPtr, cmdPrefixObj); + Tcl_IncrRefCount(cmdPrefixObj); } - cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); - Tcl_SetHashValue(hPtr, cmdPrefixObj); - Tcl_IncrRefCount(cmdPrefixObj); } - } else if (mapDict == NULL) { + } else if (mapDict) { + /* + * 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 { /* * Discover what commands are actually exported by the namespace. * What we have is an array of patterns and a hash table whose keys -- cgit v0.12 From 3eef9fcea1274b68161aa2c5ebfb6a975ac7143a Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 5 Dec 2017 15:12:05 +0000 Subject: Factor clearing of ensemble subcommand table into utility routine. --- generic/tclNamesp.c | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 1556ec9..a2e625e 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -6480,13 +6480,31 @@ MakeCachedEnsembleCommand( */ static void +ClearTable( + EnsembleConfig *ensemblePtr) +{ + Tcl_HashTable *hash = &ensemblePtr->subcommandTable; + + if (hash->numEntries != 0) { + Tcl_HashSearch search; + Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(hash, &search); + + while (hPtr != NULL) { + Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr); + Tcl_DecrRefCount(prefixObj); + hPtr = Tcl_NextHashEntry(&search); + } + ckfree((char *) ensemblePtr->subcommandArrayPtr); + } + Tcl_DeleteHashTable(hash); +} + +static void DeleteEnsembleConfig( ClientData clientData) { EnsembleConfig *ensemblePtr = clientData; Namespace *nsPtr = ensemblePtr->nsPtr; - Tcl_HashSearch search; - Tcl_HashEntry *hEnt; /* * Unlink from the ensemble chain if it has not been marked as having been @@ -6519,17 +6537,8 @@ DeleteEnsembleConfig( * Kill the pointer-containing fields. */ - if (ensemblePtr->subcommandTable.numEntries != 0) { - ckfree((char *) ensemblePtr->subcommandArrayPtr); - } - hEnt = Tcl_FirstHashEntry(&ensemblePtr->subcommandTable, &search); - while (hEnt != NULL) { - Tcl_Obj *prefixObj = Tcl_GetHashValue(hEnt); + ClearTable(ensemblePtr); - Tcl_DecrRefCount(prefixObj); - hEnt = Tcl_NextHashEntry(&search); - } - Tcl_DeleteHashTable(&ensemblePtr->subcommandTable); if (ensemblePtr->subcmdList != NULL) { Tcl_DecrRefCount(ensemblePtr->subcmdList); } @@ -6585,23 +6594,8 @@ BuildEnsembleConfig( Tcl_Obj *mapDict = ensemblePtr->subcommandDict; Tcl_Obj *subList = ensemblePtr->subcmdList; - if (hash->numEntries != 0) { - /* - * Remove pre-existing table. - */ - - Tcl_HashSearch search; - - ckfree((char *) ensemblePtr->subcommandArrayPtr); - hPtr = Tcl_FirstHashEntry(hash, &search); - while (hPtr != NULL) { - Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr); - Tcl_DecrRefCount(prefixObj); - hPtr = Tcl_NextHashEntry(&search); - } - Tcl_DeleteHashTable(hash); - Tcl_InitHashTable(hash, TCL_STRING_KEYS); - } + ClearTable(ensemblePtr); + Tcl_InitHashTable(hash, TCL_STRING_KEYS); if (subList) { int subc; -- cgit v0.12 From bb1c5fe83355d454d63db62da5797204c6cec06e Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 6 Dec 2017 13:02:32 +0000 Subject: [ce3a211dcb] Failed file normalize when tail is empty string. --- generic/tclPathObj.c | 5 ++--- tests/fileSystem.test | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index a306853..87ddfb7 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -1869,7 +1869,6 @@ Tcl_FSGetNormalizedPath( */ (void) Tcl_GetStringFromObj(dir, &cwdLen); - cwdLen += (Tcl_GetString(copy)[cwdLen] == '/'); /* Normalize the combined string. */ @@ -1890,13 +1889,13 @@ Tcl_FSGetNormalizedPath( * to a normalized head, we can more efficiently normalize the * combined path by passing over only the unnormalized tail * portion. When this is sufficient, prior developers claim - * this should be much faster. We use 'cwdLen-1' so that we are + * this should be much faster. We use 'cwdLen' so that we are * already pointing at the dir-separator that we know about. * The normalization code will actually start off directly * after that separator. */ - TclFSNormalizeToUniquePath(interp, copy, cwdLen-1); + TclFSNormalizeToUniquePath(interp, copy, cwdLen); } /* Now we need to construct the new path object. */ diff --git a/tests/fileSystem.test b/tests/fileSystem.test index d34de8f..1c507e1 100644 --- a/tests/fileSystem.test +++ b/tests/fileSystem.test @@ -508,6 +508,22 @@ test filesystem-1.52.1 {bug f9f390d0fa: file join where strep is not canonical} file normalize $x file join $x } -result /foo +test filesystem-1.53 {[Bug 3559678] - normalize when tail is empty} { + string match */ [file normalize [lindex [glob -dir [pwd] {{}}] 0]] +} 0 +test filesystem-1.54 {[Bug ce3a211dcb] - normalize when tail is empty} -setup { + set save [pwd] + cd [set home [makeDirectory ce3a211dcb]] + makeDirectory A $home + cd [lindex [glob */] 0] +} -body { + string match */A [pwd] +} -cleanup { + cd $home + removeDirectory A $home + cd $save + removeDirectory ce3a211dcb +} -result 1 test filesystem-2.0 {new native path} {unix} { foreach f [lsort [glob -nocomplain /usr/bin/c*]] { -- cgit v0.12