From dc40e6f7975ff3abcea929e29493bdc7e44c1843 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Dec 2017 11:28:25 +0000 Subject: Fix for issue [ba1419303b4c]: Delete a namespace for an ensemble having a deletion trace deletes its namespace: segmentation fault. --- generic/tclNamesp.c | 17 +++++++---------- tests/namespace.test | 13 +++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 269d06b..de10fae 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -916,6 +916,11 @@ Tcl_DeleteNamespace( Command *cmdPtr; /* + * Ensure that this namespace doesn't get deallocated in the meantime. + */ + nsPtr->refCount++; + + /* * Give anyone interested - notably TclOO - a chance to use this namespace * normally despite the fact that the namespace is going to go. Allows the * calling of destructors. Will only be called once (unless re-established @@ -1047,16 +1052,8 @@ Tcl_DeleteNamespace( #endif Tcl_DeleteHashTable(&nsPtr->cmdTable); - /* - * If the reference count is 0, then discard the namespace. - * Otherwise, mark it as "dead" so that it can't be used. - */ - - if (!nsPtr->refCount) { - NamespaceFree(nsPtr); - } else { - nsPtr->flags |= NS_DEAD; - } + nsPtr ->flags |= NS_DEAD; + TclNsDecrRefCount(nsPtr); } else { /* * Restore the ::errorInfo and ::errorCode traces. diff --git a/tests/namespace.test b/tests/namespace.test index 9fa9331..b9e6ead 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -196,6 +196,19 @@ test namespace-7.7 {Bug 1655305} -setup { interp delete slave } -result {} +test namespace-7.8 {Bug ba1419303b4c} -setup { + namespace eval ns1 { + namespace ensemble create + } + + trace add command ns1 delete { + namespace delete ns1 + } +} -body { + # No segmentation fault given --enable-symbols=mem. + namespace delete ns1 +} -result {} + test namespace-8.1 {TclTeardownNamespace, delete global namespace} { catch {interp delete test_interp} interp create test_interp -- cgit v0.12 From 7835ba29c7f535499e58023579e61eaf1232c799 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Dec 2017 18:22:59 +0000 Subject: Further fix for issue [ba1419303b4c]: Delete a namespace for an ensemble having a deletion trace deletes its namespace: segmentation fault. --- generic/tclNamesp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 0e40745..f510fed 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -1053,7 +1053,6 @@ Tcl_DeleteNamespace( Tcl_DeleteHashTable(&nsPtr->cmdTable); nsPtr ->flags |= NS_DEAD; - TclNsDecrRefCount(nsPtr); } else { /* * Restore the ::errorInfo and ::errorCode traces. @@ -1070,6 +1069,7 @@ Tcl_DeleteNamespace( nsPtr->flags &= ~(NS_DYING|NS_KILLED); } } + TclNsDecrRefCount(nsPtr); } /* -- cgit v0.12 From 5e11793221791b79a9aa3140e6a77c1fe64ec2e9 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Dec 2017 18:25:08 +0000 Subject: Further fix for issue [ba1419303b4c]: Delete a namespace for an ensemble having a deletion trace deletes its namespace: segmentation fault. --- generic/tclNamesp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index de10fae..f82d23d 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -1053,7 +1053,6 @@ Tcl_DeleteNamespace( Tcl_DeleteHashTable(&nsPtr->cmdTable); nsPtr ->flags |= NS_DEAD; - TclNsDecrRefCount(nsPtr); } else { /* * Restore the ::errorInfo and ::errorCode traces. @@ -1070,6 +1069,7 @@ Tcl_DeleteNamespace( nsPtr->flags &= ~(NS_DYING|NS_KILLED); } } + TclNsDecrRefCount(nsPtr); } /* -- cgit v0.12 From c1f84789ba402e590faed95132cf3f621c9bd0bf Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Dec 2017 18:26:40 +0000 Subject: Fix for issue [ba1419303b4c]: Delete a namespace for an ensemble having a deletion trace deletes its namespace: segmentation fault. --- generic/tclNamesp.c | 17 +++++++---------- tests/namespace.test | 13 +++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index a8d351f..542d648 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -916,6 +916,11 @@ Tcl_DeleteNamespace( Command *cmdPtr; /* + * Ensure that this namespace doesn't get deallocated in the meantime. + */ + nsPtr->refCount++; + + /* * Give anyone interested - notably TclOO - a chance to use this namespace * normally despite the fact that the namespace is going to go. Allows the * calling of destructors. Will only be called once (unless re-established @@ -1047,16 +1052,8 @@ Tcl_DeleteNamespace( #endif Tcl_DeleteHashTable(&nsPtr->cmdTable); - /* - * If the reference count is 0, then discard the namespace. - * Otherwise, mark it as "dead" so that it can't be used. - */ - - if (nsPtr->refCount == 0) { - NamespaceFree(nsPtr); - } else { - nsPtr->flags |= NS_DEAD; - } + nsPtr ->flags |= NS_DEAD; + TclNsDecrRefCount(nsPtr); } else { /* * Restore the ::errorInfo and ::errorCode traces. diff --git a/tests/namespace.test b/tests/namespace.test index ff8cd7d..f2d7061 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -196,6 +196,19 @@ test namespace-7.7 {Bug 1655305} -setup { interp delete slave } -result {} +test namespace-7.8 {Bug ba1419303b4c} -setup { + namespace eval ns1 { + namespace ensemble create + } + + trace add command ns1 delete { + namespace delete ns1 + } +} -body { + # No segmentation fault given --enable-symbols=mem. + namespace delete ns1 +} -result {} + test namespace-8.1 {TclTeardownNamespace, delete global namespace} { catch {interp delete test_interp} interp create test_interp -- cgit v0.12 From 28361a2bfe9fdba5dd0effa2c67390b21649e719 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Dec 2017 18:28:10 +0000 Subject: Further fix for issue [ba1419303b4c]: Delete a namespace for an ensemble having a deletion trace deletes its namespace: segmentation fault. --- generic/tclNamesp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 542d648..ba8e8ce 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -1053,7 +1053,6 @@ Tcl_DeleteNamespace( Tcl_DeleteHashTable(&nsPtr->cmdTable); nsPtr ->flags |= NS_DEAD; - TclNsDecrRefCount(nsPtr); } else { /* * Restore the ::errorInfo and ::errorCode traces. @@ -1070,6 +1069,7 @@ Tcl_DeleteNamespace( nsPtr->flags &= ~(NS_DYING|NS_KILLED); } } + TclNsDecrRefCount(nsPtr); } /* -- cgit v0.12 From 5a190dd003f0caaee265f6664bd1bbee842a2d66 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 21 Dec 2017 13:23:38 +0000 Subject: Remove use of compiler option "opt:nowin98". Don't use "t" as suffix any more when building extensions (but still use it for Tcl and Tk). --- win/rules.vc | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/win/rules.vc b/win/rules.vc index 7fc51c1..fac9af9 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -394,7 +394,7 @@ MSG = ^ # If INSTALLDIR set to tcl installation root dir then reset to the -# lib dir for installing extensions +# lib dir for installing extensions !if exist("$(_INSTALLDIR)\include\tcl.h") _INSTALLDIR=$(_INSTALLDIR)\lib !endif @@ -547,7 +547,7 @@ NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c # The following macros are set: # OPTIMIZATIONS - the compiler flags to be used for optimized builds # DEBUGFLAGS - the compiler flags to be used for debug builds -# LINKERFLAGS - Flags passed to the linker +# LINKERFLAGS - Flags passed to the linker # # Note that these are the compiler settings *available*, not those # that will be *used*. The latter depends on the OPTS macro settings @@ -1063,7 +1063,7 @@ STUBPREFIX = $(PROJECT)stub # Set up paths to various Tcl executables and libraries needed by extensions !if $(DOING_TCL) -TCLSHNAME = $(PROJECT)sh$(TCL_VERSION)$(SUFX).exe +TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe TCLSH = $(OUT_DIR)\$(TCLSHNAME) TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) @@ -1153,8 +1153,8 @@ tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)" !endif # $(DOING_TK) || $(NEED_TK) # Various output paths -PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib -PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) +PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX:t=).lib +PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX:t=).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib @@ -1291,7 +1291,7 @@ USE_WIDECHAR_API = 0 !endif !if $(USE_WIDECHAR_API) -COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE +COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE !endif # Like the TEA system only set this non empty for non-Tk extensions @@ -1301,7 +1301,7 @@ COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE PKGNAMEFLAGS = -DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ - -DMODULE_SCOPE=extern + -DMODULE_SCOPE=extern !endif # crt picks the C run time based on selected OPTS @@ -1394,7 +1394,7 @@ pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) # compiled with another VC version. Check for this and fix accordingly. stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) -Zl -DSTATIC_BUILD $(INCLUDES) -# Link flags +# Link flags !if $(DEBUG) ldebug = -debug -debugtype:cv @@ -1410,25 +1410,13 @@ ldebug = $(ldebug) -debug -debugtype:cv ldebug= $(ldebug) -profile !endif -### Declarations common to all linker versions +### Declarations common to all linker versions lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 lflags = $(lflags) -nodefaultlib:libucrt.lib !endif -# Old linkers (Visual C++ 6 in particular) will link for fast loading -# on Win98. Since we do not support Win98 any more, we specify nowin98 -# as recommended for NT and later. However, this is only required by -# IX86 on older compilers and only needed if we are not doing a static build. - -!if "$(MACHINE)" == "IX86" && !$(STATIC_BUILD) -!if [nmakehlp -l -opt:nowin98 $(LINKER_TESTFLAGS)] -# Align sections for PE size savings. -lflags = $(lflags) -opt:nowin98 -!endif -!endif - dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows @@ -1473,9 +1461,9 @@ RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \ -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ -DDOTVERSION=\"$(DOTVERSION)\" \ -DVERSION=\"$(VERSION)\" \ - -DSUFX=\"$(SUFX)\" \ - -DPROJECT=\"$(PROJECT)\" \ - -DPRJLIBNAME=\"$(PRJLIBNAME)\" + -DSUFX=\"$(SUFX:t=)\" \ + -DPROJECT=\"$(PROJECT)\" \ + -DPRJLIBNAME=\"$(PRJLIBNAME)\" !ifndef DEFAULT_BUILD_TARGET DEFAULT_BUILD_TARGET = $(PROJECT) @@ -1572,7 +1560,7 @@ default-shell: default-setup $(PROJECT) @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" $(DEBUGGER) $(TCLSH) -# Generation of Windows version resource +# Generation of Windows version resource !ifdef RCFILE # Note: don't use $** in below rule because there may be other dependencies @@ -1611,7 +1599,7 @@ BEGIN VALUE "OriginalFilename", PRJLIBNAME VALUE "FileVersion", DOTVERSION VALUE "ProductName", "Package " PROJECT " for Tcl" - VALUE "ProductVersion", DOTVERSION + VALUE "ProductVersion", DOTVERSION END END BLOCK "VarFileInfo" -- cgit v0.12 From 189c6453b43325f74f5b004694c79c5786d918c1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 22 Dec 2017 15:45:05 +0000 Subject: Change a few (internal) refCount/mask variables to unsigned type. --- generic/tclInt.h | 9 ++++----- generic/tclLiteral.c | 23 ++++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index de22924..2ba0493 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -545,7 +545,7 @@ typedef struct CommandTrace { struct CommandTrace *nextPtr; /* Next in list of traces associated with a * particular command. */ - unsigned int refCount; /* Used to ensure this structure is not + size_t refCount; /* Used to ensure this structure is not * deleted too early. Keeps track of how many * pieces of code have a pointer to this * structure. */ @@ -1492,11 +1492,11 @@ typedef struct LiteralEntry { * NULL if end of chain. */ Tcl_Obj *objPtr; /* Points to Tcl object that holds the * literal's bytes and length. */ - int refCount; /* If in an interpreter's global literal + size_t refCount; /* If in an interpreter's global literal * table, the number of ByteCode structures * that share the literal object; the literal * entry can be freed when refCount drops to - * 0. If in a local literal table, -1. */ + * 0. If in a local literal table, (size_t)-1. */ Namespace *nsPtr; /* Namespace in which this literal is used. We * try to avoid sharing literal non-FQ command * names among different namespaces to reduce @@ -1516,7 +1516,7 @@ typedef struct LiteralTable { * table. */ int rebuildSize; /* Enlarge table when numEntries gets to be * this large. */ - int mask; /* Mask value used in hashing function. */ + unsigned int mask; /* Mask value used in hashing function. */ } LiteralTable; /* @@ -2962,7 +2962,6 @@ MODULE_SCOPE Tcl_Obj *const * TclFetchEnsembleRoot(Tcl_Interp *interp, Tcl_Obj *const *objv, int objc, int *objcPtr); MODULE_SCOPE Tcl_Namespace * TclEnsureNamespace(Tcl_Interp *interp, Tcl_Namespace *namespacePtr); - MODULE_SCOPE void TclFinalizeAllocSubsystem(void); MODULE_SCOPE void TclFinalizeAsync(void); MODULE_SCOPE void TclFinalizeDoubleConversion(void); diff --git a/generic/tclLiteral.c b/generic/tclLiteral.c index 7acc9ad..003884d 100644 --- a/generic/tclLiteral.c +++ b/generic/tclLiteral.c @@ -186,7 +186,7 @@ TclCreateLiteral( { LiteralTable *globalTablePtr = &iPtr->literalTable; LiteralEntry *globalPtr; - int globalHash; + unsigned int globalHash; Tcl_Obj *objPtr; /* @@ -393,7 +393,8 @@ TclRegisterLiteral( LiteralEntry *globalPtr, *localPtr; Tcl_Obj *objPtr; unsigned hash; - int localHash, objIndex, new; + unsigned int localHash; + int objIndex, new; Namespace *nsPtr; if (length < 0) { @@ -537,7 +538,8 @@ TclHideLiteral( { LiteralEntry **nextPtrPtr, *entryPtr, *lPtr; LiteralTable *localTablePtr = &envPtr->localLitTable; - int localHash, length; + unsigned int localHash; + int length; const char *bytes; Tcl_Obj *newObjPtr; @@ -556,7 +558,7 @@ TclHideLiteral( lPtr->objPtr = newObjPtr; bytes = TclGetStringFromObj(newObjPtr, &length); - localHash = (HashString(bytes, length) & localTablePtr->mask); + localHash = HashString(bytes, length) & localTablePtr->mask; nextPtrPtr = &localTablePtr->buckets[localHash]; for (entryPtr=*nextPtrPtr ; entryPtr!=NULL ; entryPtr=*nextPtrPtr) { @@ -612,7 +614,7 @@ TclAddLiteralObj( lPtr = &envPtr->literalArrayPtr[objIndex]; lPtr->objPtr = objPtr; Tcl_IncrRefCount(objPtr); - lPtr->refCount = -1; /* i.e., unused */ + lPtr->refCount = (size_t)-1; /* i.e., unused */ lPtr->nextPtr = NULL; if (litPtrPtr) { @@ -809,7 +811,8 @@ TclReleaseLiteral( LiteralTable *globalTablePtr; register LiteralEntry *entryPtr, *prevPtr; const char *bytes; - int length, index; + int length; + unsigned int index; if (iPtr == NULL) { goto done; @@ -828,15 +831,13 @@ TclReleaseLiteral( for (prevPtr=NULL, entryPtr=globalTablePtr->buckets[index]; entryPtr!=NULL ; prevPtr=entryPtr, entryPtr=entryPtr->nextPtr) { if (entryPtr->objPtr == objPtr) { - entryPtr->refCount--; - /* * If the literal is no longer being used by any ByteCode, delete * the entry then remove the reference corresponding to the global * literal table entry (decrement the ref count of the object). */ - if (entryPtr->refCount == 0) { + if (entryPtr->refCount-- <= 1) { if (prevPtr == NULL) { globalTablePtr->buckets[index] = entryPtr->nextPtr; } else { @@ -954,8 +955,8 @@ RebuildLiteralTable( register LiteralEntry *entryPtr; LiteralEntry **bucketPtr; const char *bytes; - unsigned int oldSize; - int count, index, length; + unsigned int oldSize, index; + int count, length; oldSize = tablePtr->numBuckets; oldBuckets = tablePtr->buckets; -- cgit v0.12