Subject: To use a Tcl_Command token [aka (Command *)] for epoch checking, we must not permit it to be freed while we hold it or else it could be mistaken for another token allocated later that just happens to reside at the same address.

From: dgp <[email-masked]>
Date: Thu, 7 Jul 2016 18:44:56 +0000

(Command *) preservation machinery already exists, just need to use it.

An extension facing the same problem might have to rely on command delete
traces.

Earlier revisions used (Namespace *) lifetime to achieve the same
results, but that's really an indirect (possibly non-robust) path to achieving
the proper goal.

Valgrind is happy now.
---
 generic/tclEnsemble.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c
index 5c47ce3..24b6b9a 100644
--- a/generic/tclEnsemble.c
+++ b/generic/tclEnsemble.c
@@ -93,7 +93,7 @@ typedef struct {
     int epoch;                  /* Used to confirm when the data in this
                                  * really structure matches up with the
                                  * ensemble. */
-    Tcl_Command token;          /* Reference to the comamnd for which this
+    Command *token;             /* Reference to the command for which this
                                  * structure is a cache of the resolution. */
     Tcl_Obj *fix;               /* Corrected spelling, if needed. */
     Tcl_HashEntry *hPtr;        /* Direct link to entry in the subcommand
@@ -1727,7 +1727,7 @@ NsEnsembleImplementationCmdNR(
 	    EnsembleCmdRep *ensembleCmd = subObj->internalRep.twoPtrValue.ptr1;
 
 	    if (ensembleCmd->epoch == ensemblePtr->epoch &&
-		    ensembleCmd->token == ensemblePtr->token) {
+		    ensembleCmd->token == (Command *)ensemblePtr->token) {
 		prefixObj = Tcl_GetHashValue(ensembleCmd->hPtr);
 		Tcl_IncrRefCount(prefixObj);
 		if (ensembleCmd->fix) {
@@ -2404,7 +2404,8 @@ MakeCachedEnsembleCommand(
      */
 
     ensembleCmd->epoch = ensemblePtr->epoch;
-    ensembleCmd->token = ensemblePtr->token;
+    ensembleCmd->token = (Command *) ensemblePtr->token;
+    ensembleCmd->token->refCount++;
     if (fix) {
 	Tcl_IncrRefCount(fix);
     }
@@ -2790,6 +2791,7 @@ FreeEnsembleCmdRep(
 {
     EnsembleCmdRep *ensembleCmd = objPtr->internalRep.twoPtrValue.ptr1;
 
+    TclCleanupCommandMacro(ensembleCmd->token);
     if (ensembleCmd->fix) {
 	Tcl_DecrRefCount(ensembleCmd->fix);
     }
@@ -2827,6 +2829,7 @@ DupEnsembleCmdRep(
     copyPtr->internalRep.twoPtrValue.ptr1 = ensembleCopy;
     ensembleCopy->epoch = ensembleCmd->epoch;
     ensembleCopy->token = ensembleCmd->token;
+    ensembleCopy->token->refCount++;
     ensembleCopy->fix = ensembleCmd->fix;
     if (ensembleCopy->fix) {
 	Tcl_IncrRefCount(ensembleCopy->fix);
-- 
cgit v0.12