Extensions have a number of ways
to get hold of a Tcl_Command value.
The routines Tcl_(NR)Create(Obj)Command,
Tcl_GetCommandFromObj, Tcl_FindCommand,
Tcl_CreateEnsemble, and Tcl_FindEnsemble
are sources of them.
Other Tcl routines take Tcl_Command
token values as arguments.
The potential for trouble is a
situation where the command is deleted
between the time Tcl gives the
Tcl_Command value to the extension
and the time the extension passes it
back. Since a (Tcl_Command) value
is really a (Command *), in these
situations the extension may be passing
back a pointer to memory that's freed,
or even reallocated to a new purpose,
setting the stage for crashes or memory
corruption.
The Command struct has a refCount field
to keep the struct from being freed while
various parts of the Tcl internals still
hold references to it. This is not exposed
to extensions, though. The Tcl_Command value
has also not been set up to enable Tcl_Preserve().
The callers of Tcl_*Create*Command at least
have control over the Tcl_CmdDeleteProc so
they can erect some sort of notification scheme
about when their save Tcl_Command token values
are no longer safe to use.
The Tcl_Find*, Tcl_GetCommandFromObj, and
Tcl_CreateEnsemble routines don't have even
that. Perhaps a delete trace can be used to
achieve the same purpose.
There seems to be a mismatch in the
responsibilities of an extension (don't pass
back an invalid Tcl_Command) and the power
tools at its disposal (routine to test validity,
or notification when validity is going away,
or documented examples of how to use what tools
do exist effectively) to live up to those responsibilities.
I put this in the [namespace] category because
I've encountered this problem with tokens
returned by Tcl_CreateEnsemble.
One idea how callers might deal
with the current situation. Rather
than directly store a Tcl_Command,
arrange to store an unshared Tcl_Obj
and use Tcl_GetCommandFromObj() to
manipulate it into the "cmdName"
Tcl_ObjType. The intrep management
builtin to that Tcl_ObjType will
take care of the Command refCounts
to keep the struct alive. Whenever
the Tcl_Command value is needed,
another call to Tcl_GetCommandFromObj()
will fetch it. When really done with
the value, just Tcl_DecrRefCount to make
the Tcl_Obj and its intrep go away.
There's probably still some ugliness
on how to handle renames. Hmmm....
Looking from the other side of
the fence, I wonder if the solution
might be for the Tcl_Command token
to no longer be a (Command *) value
which can become invalid, but instead
be a TclHandle of some suitable kind.
Seems the TclHandle idea still would
burden the caller with the responsibility
of TclHandlePreserve/Release calls.