From 1d4f551278f3f36f063591ecc1a6bd2e7964b14f Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 12 Aug 2020 13:28:08 +0000 Subject: Fix for [3422267ed6b7], segmentation fault with imported alias. --- generic/tclNamesp.c | 7 ++++++- generic/tclProc.c | 7 +++++++ tests/interp.test | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 26dca62..fea23aa 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -959,7 +959,7 @@ Tcl_DeleteNamespace( /* * If the namespace has associated ensemble commands, delete them first. * This leaves the actual contents of the namespace alone (unless they are - * linked ensemble commands, of course). Note that this code is actually + * linked ensemble commands, of course). This code is * reentrant so command delete traces won't purturb things badly. */ @@ -1770,7 +1770,9 @@ DoImport( TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; + cmdPtr->refCount++; dataPtr->selfPtr = (Command *) importedCmd; + dataPtr->selfPtr->refCount++; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); @@ -1781,6 +1783,7 @@ DoImport( refPtr = (ImportRef *)ckalloc(sizeof(ImportRef)); refPtr->importedCmdPtr = (Command *) importedCmd; + refPtr->importedCmdPtr->refCount++; refPtr->nextPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = refPtr; } else { @@ -2076,7 +2079,9 @@ DeleteImportedCmd( } else { prevPtr->nextPtr = refPtr->nextPtr; } + TclCleanupCommandMacro(refPtr->importedCmdPtr); ckfree(refPtr); + TclCleanupCommandMacro(selfPtr) ckfree(dataPtr); return; } diff --git a/generic/tclProc.c b/generic/tclProc.c index 0d67c37..150d036 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -215,6 +215,7 @@ Tcl_ProcObjCmd( */ procPtr->cmdPtr = (Command *) cmd; + procPtr->cmdPtr->refCount++; /* * TIP #280: Remember the line the procedure body is starting on. In a @@ -2154,6 +2155,12 @@ TclProcCleanupProc( ckfree(localPtr); localPtr = nextPtr; } + /* + * TclOOMethod.c:clOOMakeProcMethod sets cmdPtr to NULL + */ + if (procPtr->cmdPtr) { + TclCleanupCommandMacro(procPtr->cmdPtr); + } ckfree(procPtr); /* diff --git a/tests/interp.test b/tests/interp.test index 599ac08..35f3390 100644 --- a/tests/interp.test +++ b/tests/interp.test @@ -3664,6 +3664,13 @@ test interp-38.8 {interp debug basic setup} -body { } -returnCodes { error } -result {wrong # args: should be "interp debug path ?-frame ?bool??"} + +test interp-39.0 { + no segmentation fault when a command is deleted +} -body { +} -cleanup { +} -result 1 + # cleanup unset -nocomplain hidden_cmds -- cgit v0.12 From 80c4d66b217ec43299960d17a40f07d4cfd870bf Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 12 Aug 2020 13:31:16 +0000 Subject: body of test case for [3422267ed6b79922]. --- tests/interp.test | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/interp.test b/tests/interp.test index 35f3390..9287756 100644 --- a/tests/interp.test +++ b/tests/interp.test @@ -3668,6 +3668,36 @@ test interp-38.8 {interp debug basic setup} -body { test interp-39.0 { no segmentation fault when a command is deleted } -body { + variable res {} + + proc p1 args { + return success + } + namespace eval ns1 { + namespace export * + } + interp alias {} [namespace current]::ns1::p2 {} [namespace current]::p1 + namespace eval ns2 { + namespace import [namespace parent]::ns1::p2 + } + proc ondelete {oldname newname op} { + variable res + namespace delete ns1 + catch { + ns1::p2 + } res + } + + trace add command ns2::p2 delete [namespace which ondelete] + rename ns2::p2 {} + rename p1 {} + if { + [string match {*invalid command name*ns1::p2*} $res] + } { + return 1 + } else { + return $res + } } -cleanup { } -result 1 -- cgit v0.12 From 3c1b7f78dc3d31142226b8c29cce38d5d3a86f03 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Aug 2020 12:42:38 +0000 Subject: Backout uncomplete fix for [3422267ed6b79922]: segmentation fault from deleting the the target of an imported alias during a trace on the target of the alias. Since it causes build failures. --- generic/tclNamesp.c | 7 +------ generic/tclProc.c | 7 ------- tests/interp.test | 37 ------------------------------------- 3 files changed, 1 insertion(+), 50 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index fea23aa..26dca62 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -959,7 +959,7 @@ Tcl_DeleteNamespace( /* * If the namespace has associated ensemble commands, delete them first. * This leaves the actual contents of the namespace alone (unless they are - * linked ensemble commands, of course). This code is + * linked ensemble commands, of course). Note that this code is actually * reentrant so command delete traces won't purturb things badly. */ @@ -1770,9 +1770,7 @@ DoImport( TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; - cmdPtr->refCount++; dataPtr->selfPtr = (Command *) importedCmd; - dataPtr->selfPtr->refCount++; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); @@ -1783,7 +1781,6 @@ DoImport( refPtr = (ImportRef *)ckalloc(sizeof(ImportRef)); refPtr->importedCmdPtr = (Command *) importedCmd; - refPtr->importedCmdPtr->refCount++; refPtr->nextPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = refPtr; } else { @@ -2079,9 +2076,7 @@ DeleteImportedCmd( } else { prevPtr->nextPtr = refPtr->nextPtr; } - TclCleanupCommandMacro(refPtr->importedCmdPtr); ckfree(refPtr); - TclCleanupCommandMacro(selfPtr) ckfree(dataPtr); return; } diff --git a/generic/tclProc.c b/generic/tclProc.c index 150d036..0d67c37 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -215,7 +215,6 @@ Tcl_ProcObjCmd( */ procPtr->cmdPtr = (Command *) cmd; - procPtr->cmdPtr->refCount++; /* * TIP #280: Remember the line the procedure body is starting on. In a @@ -2155,12 +2154,6 @@ TclProcCleanupProc( ckfree(localPtr); localPtr = nextPtr; } - /* - * TclOOMethod.c:clOOMakeProcMethod sets cmdPtr to NULL - */ - if (procPtr->cmdPtr) { - TclCleanupCommandMacro(procPtr->cmdPtr); - } ckfree(procPtr); /* diff --git a/tests/interp.test b/tests/interp.test index 9287756..599ac08 100644 --- a/tests/interp.test +++ b/tests/interp.test @@ -3664,43 +3664,6 @@ test interp-38.8 {interp debug basic setup} -body { } -returnCodes { error } -result {wrong # args: should be "interp debug path ?-frame ?bool??"} - -test interp-39.0 { - no segmentation fault when a command is deleted -} -body { - variable res {} - - proc p1 args { - return success - } - namespace eval ns1 { - namespace export * - } - interp alias {} [namespace current]::ns1::p2 {} [namespace current]::p1 - namespace eval ns2 { - namespace import [namespace parent]::ns1::p2 - } - proc ondelete {oldname newname op} { - variable res - namespace delete ns1 - catch { - ns1::p2 - } res - } - - trace add command ns2::p2 delete [namespace which ondelete] - rename ns2::p2 {} - rename p1 {} - if { - [string match {*invalid command name*ns1::p2*} $res] - } { - return 1 - } else { - return $res - } -} -cleanup { -} -result 1 - # cleanup unset -nocomplain hidden_cmds -- cgit v0.12 From acfbbfa01955b1e6807428aef20496d83af43d17 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Aug 2020 14:20:54 +0000 Subject: More usage of TclNewIntObj() macro --- generic/tclCmdMZ.c | 2 +- generic/tclCompExpr.c | 4 ++-- generic/tclDate.c | 4 ++-- generic/tclExecute.c | 6 +++--- generic/tclGetDate.y | 4 ++-- generic/tclIORChan.c | 8 +++++--- generic/tclLink.c | 10 +++++----- generic/tclOOBasic.c | 2 +- generic/tclPkg.c | 3 ++- generic/tclProcess.c | 12 ++++++------ generic/tclTrace.c | 4 ++-- generic/tclVar.c | 2 +- 12 files changed, 32 insertions(+), 29 deletions(-) diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index fe7cddd..f95dd12 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -4311,7 +4311,7 @@ Tcl_TimeRateObjCmd( */ measureOverhead = 0; - Tcl_SetObjResult(interp, Tcl_NewLongObj(0)); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(0)); return TCL_OK; } diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index 4fb41fc..74610c7 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -2725,7 +2725,7 @@ TclVariadicOpCmd( Tcl_Obj *const *litObjPtrPtr = litObjv; if (lexeme == EXPON) { - litObjv[1] = Tcl_NewIntObj(occdPtr->i.identity); + TclNewIntObj(litObjv[1], occdPtr->i.identity); Tcl_IncrRefCount(litObjv[1]); decrMe = 1; litObjv[0] = objv[1]; @@ -2741,7 +2741,7 @@ TclVariadicOpCmd( if (lexeme == DIVIDE) { litObjv[0] = Tcl_NewDoubleObj(1.0); } else { - litObjv[0] = Tcl_NewIntObj(occdPtr->i.identity); + TclNewIntObj(litObjv[0], occdPtr->i.identity); } Tcl_IncrRefCount(litObjv[0]); litObjv[1] = objv[1]; diff --git a/generic/tclDate.c b/generic/tclDate.c index e9ef9bd..f8552a3 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -2501,12 +2501,12 @@ TclDateerror( Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); Tcl_AppendToObj(infoPtr->messages, s, -1); Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); - t = Tcl_NewIntObj(location->first_column); + TclNewIntObj(t, location->first_column); Tcl_IncrRefCount(t); Tcl_AppendObjToObj(infoPtr->messages, t); Tcl_DecrRefCount(t); Tcl_AppendToObj(infoPtr->messages, "-", -1); - t = Tcl_NewIntObj(location->last_column); + TclNewIntObj(t, location->last_column); Tcl_IncrRefCount(t); Tcl_AppendObjToObj(infoPtr->messages, t); Tcl_DecrRefCount(t); diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 4c25397..0f1c2cc 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -3635,7 +3635,7 @@ TEBCresume( case INST_INCR_SCALAR_STK_IMM: case INST_INCR_STK_IMM: increment = TclGetInt1AtPtr(pc+1); - incrPtr = Tcl_NewIntObj(increment); + TclNewIntObj(incrPtr, increment); Tcl_IncrRefCount(incrPtr); pcAdjustment = 2; @@ -3670,7 +3670,7 @@ TEBCresume( case INST_INCR_ARRAY1_IMM: opnd = TclGetUInt1AtPtr(pc+1); increment = TclGetInt1AtPtr(pc+2); - incrPtr = Tcl_NewIntObj(increment); + TclNewIntObj(incrPtr, increment); Tcl_IncrRefCount(incrPtr); pcAdjustment = 3; @@ -7022,7 +7022,7 @@ TEBCresume( if (valuePtr == NULL) { Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd)); } else { - value2Ptr = Tcl_NewIntObj(opnd); + TclNewIntObj(value2Ptr, opnd); Tcl_IncrRefCount(value2Ptr); if (Tcl_IsShared(valuePtr)) { valuePtr = Tcl_DuplicateObj(valuePtr); diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index c06e53a..33b23ae 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -716,12 +716,12 @@ TclDateerror( Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); Tcl_AppendToObj(infoPtr->messages, s, -1); Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); - t = Tcl_NewIntObj(location->first_column); + TclNewIntObj(t, location->first_column); Tcl_IncrRefCount(t); Tcl_AppendObjToObj(infoPtr->messages, t); Tcl_DecrRefCount(t); Tcl_AppendToObj(infoPtr->messages, "-", -1); - t = Tcl_NewIntObj(location->last_column); + TclNewIntObj(t, location->last_column); Tcl_IncrRefCount(t); Tcl_AppendObjToObj(infoPtr->messages, t); Tcl_DecrRefCount(t); diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 8a5675a..c622afa 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -1365,7 +1365,7 @@ ReflectInput( Tcl_Preserve(rcPtr); - toReadObj = Tcl_NewIntObj(toRead); + TclNewIntObj(toReadObj, toRead); Tcl_IncrRefCount(toReadObj); if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK) { @@ -3047,8 +3047,10 @@ ForwardProc( } case ForwardedInput: { - Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead); - Tcl_IncrRefCount(toReadObj); + Tcl_Obj *toReadObj; + + TclNewIntObj(toReadObj, paramPtr->input.toRead); + Tcl_IncrRefCount(toReadObj); Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK){ diff --git a/generic/tclLink.c b/generic/tclLink.c index 4256f84..c763218 100644 --- a/generic/tclLink.c +++ b/generic/tclLink.c @@ -1296,7 +1296,7 @@ ObjValue( memcpy(linkPtr->lastValue.aryPtr, linkPtr->addr, linkPtr->bytes); objv = (Tcl_Obj **)ckalloc(linkPtr->numElems * sizeof(Tcl_Obj *)); for (i=0; i < linkPtr->numElems; i++) { - objv[i] = Tcl_NewIntObj(linkPtr->lastValue.iPtr[i]); + TclNewIntObj(objv[i], linkPtr->lastValue.iPtr[i]); } resultObj = Tcl_NewListObj(linkPtr->numElems, objv); ckfree(objv); @@ -1348,7 +1348,7 @@ ObjValue( memcpy(linkPtr->lastValue.aryPtr, linkPtr->addr, linkPtr->bytes); objv = (Tcl_Obj **)ckalloc(linkPtr->numElems * sizeof(Tcl_Obj *)); for (i=0; i < linkPtr->numElems; i++) { - objv[i] = Tcl_NewIntObj(linkPtr->lastValue.cPtr[i]); + TclNewIntObj(objv[i], linkPtr->lastValue.cPtr[i]); } resultObj = Tcl_NewListObj(linkPtr->numElems, objv); ckfree(objv); @@ -1361,7 +1361,7 @@ ObjValue( memcpy(linkPtr->lastValue.aryPtr, linkPtr->addr, linkPtr->bytes); objv = (Tcl_Obj **)ckalloc(linkPtr->numElems * sizeof(Tcl_Obj *)); for (i=0; i < linkPtr->numElems; i++) { - objv[i] = Tcl_NewIntObj(linkPtr->lastValue.ucPtr[i]); + TclNewIntObj(objv[i], linkPtr->lastValue.ucPtr[i]); } resultObj = Tcl_NewListObj(linkPtr->numElems, objv); ckfree(objv); @@ -1374,7 +1374,7 @@ ObjValue( memcpy(linkPtr->lastValue.aryPtr, linkPtr->addr, linkPtr->bytes); objv = (Tcl_Obj **)ckalloc(linkPtr->numElems * sizeof(Tcl_Obj *)); for (i=0; i < linkPtr->numElems; i++) { - objv[i] = Tcl_NewIntObj(linkPtr->lastValue.sPtr[i]); + TclNewIntObj(objv[i], linkPtr->lastValue.sPtr[i]); } resultObj = Tcl_NewListObj(linkPtr->numElems, objv); ckfree(objv); @@ -1387,7 +1387,7 @@ ObjValue( memcpy(linkPtr->lastValue.aryPtr, linkPtr->addr, linkPtr->bytes); objv = (Tcl_Obj **)ckalloc(linkPtr->numElems * sizeof(Tcl_Obj *)); for (i=0; i < linkPtr->numElems; i++) { - objv[i] = Tcl_NewIntObj(linkPtr->lastValue.usPtr[i]); + TclNewIntObj(objv[i], linkPtr->lastValue.usPtr[i]); } resultObj = Tcl_NewListObj(linkPtr->numElems, objv); ckfree(objv); diff --git a/generic/tclOOBasic.c b/generic/tclOOBasic.c index 9f7b526..b866c2c 100644 --- a/generic/tclOOBasic.c +++ b/generic/tclOOBasic.c @@ -1249,7 +1249,7 @@ TclOOSelfObjCmd( } case SELF_CALL: result[0] = TclOORenderCallChain(interp, contextPtr->callPtr); - result[1] = Tcl_NewIntObj(contextPtr->index); + TclNewIntObj(result[1], contextPtr->index); Tcl_SetObjResult(interp, Tcl_NewListObj(2, result)); return TCL_OK; } diff --git a/generic/tclPkg.c b/generic/tclPkg.c index b39224e..bdd9a86 100644 --- a/generic/tclPkg.c +++ b/generic/tclPkg.c @@ -905,8 +905,9 @@ SelectPackageFinal( } } } else if (result != TCL_ERROR) { - Tcl_Obj *codePtr = Tcl_NewIntObj(result); + Tcl_Obj *codePtr; + TclNewIntObj(codePtr, result); Tcl_SetObjResult(interp, Tcl_ObjPrintf( "attempt to provide package %s %s failed:" " bad return code: %s", diff --git a/generic/tclProcess.c b/generic/tclProcess.c index 5bf0af8..c0f21e3 100644 --- a/generic/tclProcess.c +++ b/generic/tclProcess.c @@ -267,8 +267,8 @@ WaitProcessStatus( "child process exited abnormally", -1); if (errorObjPtr) { errorStrings[0] = Tcl_NewStringObj("CHILDSTATUS", -1); - errorStrings[1] = Tcl_NewIntObj(resolvedPid); - errorStrings[2] = Tcl_NewIntObj(WEXITSTATUS(waitStatus)); + TclNewIntObj(errorStrings[1], resolvedPid); + TclNewIntObj(errorStrings[2], WEXITSTATUS(waitStatus)); *errorObjPtr = Tcl_NewListObj(3, errorStrings); } } @@ -286,7 +286,7 @@ WaitProcessStatus( "child killed: %s", msg); if (errorObjPtr) { errorStrings[0] = Tcl_NewStringObj("CHILDKILLED", -1); - errorStrings[1] = Tcl_NewIntObj(resolvedPid); + TclNewIntObj(errorStrings[1], resolvedPid); errorStrings[2] = Tcl_NewStringObj(Tcl_SignalId(WTERMSIG(waitStatus)), -1); errorStrings[3] = Tcl_NewStringObj(msg, -1); *errorObjPtr = Tcl_NewListObj(4, errorStrings); @@ -305,7 +305,7 @@ WaitProcessStatus( "child suspended: %s", msg); if (errorObjPtr) { errorStrings[0] = Tcl_NewStringObj("CHILDSUSP", -1); - errorStrings[1] = Tcl_NewIntObj(resolvedPid); + TclNewIntObj(errorStrings[1], resolvedPid); errorStrings[2] = Tcl_NewStringObj(Tcl_SignalId(WSTOPSIG(waitStatus)), -1); errorStrings[3] = Tcl_NewStringObj(msg, -1); *errorObjPtr = Tcl_NewListObj(4, errorStrings); @@ -326,7 +326,7 @@ WaitProcessStatus( errorStrings[1] = Tcl_NewStringObj("OPERATION", -1); errorStrings[2] = Tcl_NewStringObj("EXEC", -1); errorStrings[3] = Tcl_NewStringObj("ODDWAITRESULT", -1); - errorStrings[4] = Tcl_NewIntObj(resolvedPid); + TclNewIntObj(errorStrings[4], resolvedPid); *errorObjPtr = Tcl_NewListObj(5, errorStrings); } return TCL_PROCESS_UNKNOWN_STATUS; @@ -378,7 +378,7 @@ BuildProcessStatusObj( * Abnormal exit, return {TCL_ERROR msg error} */ - resultObjs[0] = Tcl_NewIntObj(TCL_ERROR); + TclNewIntObj(resultObjs[0], TCL_ERROR); resultObjs[1] = info->msg; resultObjs[2] = info->error; return Tcl_NewListObj(3, resultObjs); diff --git a/generic/tclTrace.c b/generic/tclTrace.c index e05fa69..9896e0e 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -1848,7 +1848,7 @@ TraceExecutionProc( * Append result code. */ - resultCode = Tcl_NewIntObj(code); + TclNewIntObj(resultCode, code); resultCodeStr = Tcl_GetString(resultCode); Tcl_DStringAppendElement(&cmd, resultCodeStr); Tcl_DecrRefCount(resultCode); @@ -1976,7 +1976,7 @@ TraceVarProc( int rewind = ((Interp *)interp)->execEnvPtr->rewind; /* - * We might call Tcl_Eval() below, and that might evaluate [trace vdelete] + * We might call Tcl_EvalEx() below, and that might evaluate [trace vdelete] * which might try to free tvarPtr. We want to use tvarPtr until the end * of this function, so we use Tcl_Preserve() and Tcl_Release() to be sure * it is not freed while we still need it. diff --git a/generic/tclVar.c b/generic/tclVar.c index 72724a4..2818fc9 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -2322,7 +2322,7 @@ TclPtrIncrObjVarIdx( VarHashRefCount(varPtr)--; } if (varValuePtr == NULL) { - varValuePtr = Tcl_NewIntObj(0); + TclNewIntObj(varValuePtr, 0); } if (Tcl_IsShared(varValuePtr)) { /* Copy on write */ -- cgit v0.12 From a5455c136a2b022903089f85ebc28327fe31898e Mon Sep 17 00:00:00 2001 From: pooryorick Date: Sun, 16 Aug 2020 10:04:44 +0000 Subject: Fix for [688fcc7082fa], memory error during deletion of imported routine. --- generic/tclBasic.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 4ee2ca0..2b1bae9 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3547,6 +3547,19 @@ Tcl_DeleteCommandFromToken( iPtr->compileEpoch++; } + if (!(cmdPtr->flags & CMD_REDEF_IN_PROGRESS)) { + /* + * Delete any imports of this routine before deleting this routine itself. + * See issue 688fcc7082fa. + */ + for (refPtr = cmdPtr->importRefPtr; refPtr != NULL; + refPtr = nextRefPtr) { + nextRefPtr = refPtr->nextPtr; + importCmd = (Tcl_Command) refPtr->importedCmdPtr; + Tcl_DeleteCommandFromToken(interp, importCmd); + } + } + if (cmdPtr->deleteProc != NULL) { /* * Delete the command's client data. If this was an imported command @@ -3567,20 +3580,6 @@ Tcl_DeleteCommandFromToken( } /* - * If this command was imported into other namespaces, then imported - * commands were created that refer back to this command. Delete these - * imported commands now. - */ - if (!(cmdPtr->flags & CMD_REDEF_IN_PROGRESS)) { - for (refPtr = cmdPtr->importRefPtr; refPtr != NULL; - refPtr = nextRefPtr) { - nextRefPtr = refPtr->nextPtr; - importCmd = (Tcl_Command) refPtr->importedCmdPtr; - Tcl_DeleteCommandFromToken(interp, importCmd); - } - } - - /* * Don't use hPtr to delete the hash entry here, because it's possible * that the deletion callback renamed the command. Instead, use * cmdPtr->hptr, and make sure that no-one else has already deleted the -- cgit v0.12