aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jim.c74
-rw-r--r--jim.h.in1
-rw-r--r--regtest.tcl6
3 files changed, 46 insertions, 35 deletions
diff --git a/jim.c b/jim.c
index eb1a407..3ee76e9 100644
--- a/jim.c
+++ b/jim.c
@@ -3070,26 +3070,35 @@ ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
/* -----------------------------------------------------------------------------
* Commands
* ---------------------------------------------------------------------------*/
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+ cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+ if (--cmdPtr->inUse == 0) {
+ if (cmdPtr->cmdProc == NULL) {
+ Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
+ if (cmdPtr->staticVars) {
+ Jim_FreeHashTable(cmdPtr->staticVars);
+ Jim_Free(cmdPtr->staticVars);
+ }
+ } else if (cmdPtr->delProc != NULL) {
+ /* If it was a C coded command, call the delProc if any */
+ cmdPtr->delProc(interp, cmdPtr->privData);
+ }
+ Jim_Free(cmdPtr);
+ }
+}
/* Commands HashTable Type.
*
* Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
static void Jim_CommandsHT_ValDestructor(void *interp, void *val)
{
- Jim_Cmd *cmdPtr = (void*) val;
-
- if (cmdPtr->cmdProc == NULL) {
- Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
- Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
- if (cmdPtr->staticVars) {
- Jim_FreeHashTable(cmdPtr->staticVars);
- Jim_Free(cmdPtr->staticVars);
- }
- } else if (cmdPtr->delProc != NULL) {
- /* If it was a C coded command, call the delProc if any */
- cmdPtr->delProc(interp, cmdPtr->privData);
- }
- Jim_Free(val);
+ JimDecrCmdRefCount(interp, val);
}
static const Jim_HashTableType JimCommandsHashTableType = {
@@ -3106,35 +3115,22 @@ static const Jim_HashTableType JimCommandsHashTableType = {
int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
{
- Jim_HashEntry *he;
Jim_Cmd *cmdPtr;
- he = Jim_FindHashEntry(&interp->commands, cmdName);
- if (he == NULL) { /* New command to create */
- cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
- Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
- } else {
+ if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
+ /* Command existed so incr proc epoch */
Jim_InterpIncrProcEpoch(interp);
- /* Free the arglist/body objects if it was a Tcl procedure */
- cmdPtr = he->val;
- if (cmdPtr->cmdProc == NULL) {
- Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
- Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
- if (cmdPtr->staticVars) {
- Jim_FreeHashTable(cmdPtr->staticVars);
- Jim_Free(cmdPtr->staticVars);
- }
- cmdPtr->staticVars = NULL;
- } else if (cmdPtr->delProc != NULL) {
- /* If it was a C coded command, call the delProc if any */
- cmdPtr->delProc(interp, cmdPtr->privData);
- }
}
+ cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
/* Store the new details for this proc */
cmdPtr->delProc = delProc;
cmdPtr->cmdProc = cmdProc;
cmdPtr->privData = privData;
+ cmdPtr->inUse = 1;
+
+ Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
/* There is no need to increment the 'proc epoch' because
* creation of a new procedure can never affect existing
@@ -3159,6 +3155,7 @@ int Jim_CreateProcedure(Jim_Interp *interp, const char *cmdName,
cmdPtr->args = args;
cmdPtr->rightArity = rightArity;
cmdPtr->staticVars = NULL;
+ cmdPtr->inUse = 1;
/* Create the statics hash table. */
if (staticsListObjPtr) {
@@ -3218,7 +3215,10 @@ int Jim_CreateProcedure(Jim_Interp *interp, const char *cmdName,
/* Add the new command */
- /* it may already exist, so we try to delete the old one */
+ /* It may already exist, so we try to delete the old one.
+ * Note that reference count means that it won't be deleted yet if
+ * it exists in the call stack
+ */
if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
/* There was an old procedure with the same name, this requires
* a 'proc epoch' update. */
@@ -8683,6 +8683,7 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
retcode = JimUnknown(interp, objc, objv);
} else {
/* Call it -- Make sure result is an empty object. */
+ JimIncrCmdRefCount(cmdPtr);
Jim_SetEmptyResult(interp);
if (cmdPtr->cmdProc) {
interp->cmdPrivData = cmdPtr->privData;
@@ -8690,6 +8691,7 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
} else {
retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
}
+ JimDecrCmdRefCount(interp, cmdPtr);
}
/* Decr refcount of arguments and return the retcode */
for (i = 0; i < objc; i++)
@@ -9059,6 +9061,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
if (cmd != NULL) {
/* Call it -- Make sure result is an empty object. */
+ JimIncrCmdRefCount(cmd);
Jim_SetEmptyResult(interp);
if (cmd->cmdProc) {
interp->cmdPrivData = cmd->privData;
@@ -9066,6 +9069,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
} else {
retcode = JimCallProcedure(interp, cmd, argc, argv);
}
+ JimDecrCmdRefCount(interp, cmd);
} else {
/* Call [unknown] */
retcode = JimUnknown(interp, argc, argv);
diff --git a/jim.h.in b/jim.h.in
index e578c07..a9fc9d4 100644
--- a/jim.h.in
+++ b/jim.h.in
@@ -464,6 +464,7 @@ typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
* it's a Tcl procedure with the arglist and body represented by the
* two objects referenced by arglistObjPtr and bodyoObjPtr. */
typedef struct Jim_Cmd {
+ int inUse; /* Reference count */
Jim_CmdProc cmdProc; /* Not-NULL for a C command. */
void *privData; /* Only used for C commands. */
Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
diff --git a/regtest.tcl b/regtest.tcl
index 7651988..4bfcba6 100644
--- a/regtest.tcl
+++ b/regtest.tcl
@@ -68,6 +68,12 @@ catch {package require aio}
expr {1 || !0}
puts "TEST 10 PASSED"
+# REGTEST 11
+# 14 Feb 2010 - access static variable in deleted proc
+proc a {} {{x 1}} { rename a ""; incr x }
+a
+puts "TEST 11 PASSED"
+
# TAKE THE FOLLOWING puts AS LAST LINE
puts "--- ALL TESTS PASSED ---"