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

  1. proc ::cb {cmd args} {
  2. # onEnter:
  3. # cmdPtr->cmdEpoch = 1 (because Tcl_DeleteTokenFromCommand bumped it *before* executing traces (deleteProc)
  4. # resPtr->cmdEpoch = 0
  5.  
  6. # namespace origin will call Tcl_GetCommandFromObj (so checking Tcl_Obj cmd's cmdtype intrep)
  7. namespace origin $cmd
  8. # cmdPtr->cmdEpoch == resPtr->cmdEpoch evaluates to false, intrep is updated using the old cmd under deletion (!), then:
  9. # cmdPtr->cmdEpoch = 1
  10. # resPtr->cmdEpoch = 1 (because cmd under deletion is used)
  11. # Sooo: from that time on, unless there is a second cmdEpoch++
  12. # (2!=1) once traces (deleteProc) have been run, the Tcl_Obj
  13. # behind cmd will keep returning the wrongly? re-cached old cmd.
  14. }
  15.  
  16. set cmd ::e
  17.  
  18. set script {
  19. proc $cmd args {;}
  20. $cmd
  21. trace add command $cmd delete [list ::cb $cmd]
  22. 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
  23. }
  24.  
  25. # eval script block so that cmd becomes cmdType early.
  26. eval $script
  27.  
  28. ##
  29. ## What we see (for our deleteProc, not traces) when creating a
  30. ## same-named cmd (::e) using $cmd, the Tcl_Objs cached cmdPtr points
  31. ## to the old cmd (which is a zombie once Tcl_DeleteCommandFromToken
  32. ## has completed.) So far, our deleteProc for the old cmd (::e) has
  33. ## not cmdEpoch++ on its own. We do so now and the problem goes away.
  34. ##
  35.  

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.