Posted to tcl by mr_calvin at Thu Dec 01 14:34:40 GMT 2016view pretty

proc ::cb {cmd args} {
    # onEnter:
    # cmdPtr->cmdEpoch = 1 (because Tcl_DeleteTokenFromCommand bumped it *before* executing traces (deleteProc)
    # resPtr->cmdEpoch = 0

    # namespace origin will call Tcl_GetCommandFromObj (so checking Tcl_Obj cmd's cmdtype intrep)
    namespace origin $cmd
    # cmdPtr->cmdEpoch == resPtr->cmdEpoch evaluates to false, intrep is updated using the old cmd under deletion (!), then:
    # cmdPtr->cmdEpoch = 1
    # resPtr->cmdEpoch = 1 (because cmd under deletion is used)
    # Sooo: from that time on, unless there is a second cmdEpoch++
    # (2!=1) once traces (deleteProc) have been run, the Tcl_Obj
    # behind cmd will keep returning the wrongly? re-cached old cmd.
}

set cmd ::e

set script {
    proc $cmd args {;}
    $cmd
    trace add command $cmd delete [list ::cb $cmd]
    rename $cmd ""; # trigger Tcl_DeleteTokenFromCommand + traces; rename (if I get it correctly) will also cmdEpoch++ a second time; so Tcl is fine, but we were not
}

# eval script block so that cmd becomes cmdType early.
eval $script

##
## What we see (for our deleteProc, not traces) when creating a
## same-named cmd (::e) using $cmd, the Tcl_Objs cached cmdPtr points
## to the old cmd (which is a zombie once Tcl_DeleteCommandFromToken
## has completed.) So far, our deleteProc for the old cmd (::e) has
## not cmdEpoch++ on its own. We do so now and the problem goes away.
## 

Comments

Posted by mr_calvin at Fri Dec 02 11:20:03 GMT 2016 [text] [code]

Hi Don, I tested http://core.tcl.tk/tcl/info/d3f2f88f49d64089. This solves the issue from our side (and cleans up cmdEpochs' state during deleteProc/delete traces). One thing: the repeated cmdEpoch++ before the final return is not necessary. one cmdEpoch++ is sufficient (i tested it from our side). just a left-over? (the second cmdEpoch++ I hinted above is only necessary because the first cmdEpoch++ occurred too early, before the deleteProc/ delete traces). thx.