- fix illegal memory access in unregister_command function
[fw/openocd] / src / helper / command.c
index 9ade320c669bfdc3442a290d1622fa094df73cfc..cba05f1672ba25e0762c82e70faee44c26e99e44 100644 (file)
@@ -64,7 +64,6 @@ static void tcl_output(void *privData, const char *file, int line, const char *f
 
 extern command_context_t *global_cmd_ctx;
 
-
 static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
        /* the private data is stashed in the interp structure */
@@ -75,10 +74,20 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        int nwords;
        char **words;
 
+       /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
+        * get overwritten by running other Jim commands! Treat it as an
+        * emphemeral global variable that is used in lieu of an argument
+        * to the fn and fish it out manually.
+        */
+       c = interp->cmdPrivData;
+       if (c==NULL)
+       {
+               LOG_ERROR("BUG: interp->cmdPrivData==NULL");
+               return JIM_ERR;
+       }
        target_call_timer_callbacks_now();
        LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
 
-       c = interp->cmdPrivData;
        LOG_DEBUG("script_command - %s", c->name);
 
        words = malloc(sizeof(char *) * argc);
@@ -138,6 +147,9 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        return (retval==ERROR_OK)?JIM_OK:JIM_ERR;
 }
 
+/* nice short description of source file */
+#define __THIS__FILE__ "command.c"
+
 command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
 {
        command_t *c, *p;
@@ -213,7 +225,7 @@ command_t* register_command(command_context_t *context, command_t *parent, char
 
        /* we now need to add an overrideable proc */
        const char *override_name=alloc_printf("proc %s%s%s {args} {if {[catch {eval \"ocd_%s%s%s $args\"}]==0} {return \"\"} else { return -code error }", t1, t2, t3, t1, t2, t3);
-       Jim_Eval_Named(interp, override_name, __FILE__, __LINE__ );
+       Jim_Eval_Named(interp, override_name, __THIS__FILE__, __LINE__ );
        free((void *)override_name);
 
        /* accumulate help text in Tcl helptext list.  */
@@ -277,8 +289,10 @@ int unregister_command(command_context_t *context, char *name)
                return ERROR_INVALID_ARGUMENTS;
 
        /* find command */
-       for (c = context->commands; c; c = c->next)
-       {
+       c = context->commands;
+       
+       while(NULL != c)
+       {               
                if (strcmp(name, c->name) == 0)
                {
                        /* unlink command */
@@ -288,26 +302,32 @@ int unregister_command(command_context_t *context, char *name)
                        }
                        else
                        {
+                               /* first element in command list */
                                context->commands = c->next;
                        }
-
+                       
                        /* unregister children */
-                       if (c->children)
+                       while(NULL != c->children)
                        {
-                               for (c2 = c->children; c2; c2 = c2->next)
-                               {
-                                       free(c2->name);
-                                       free(c2);
-                               }
+                               c2 = c->children;
+                               c->children = c->children->next;
+                               free(c2->name);
+                               c2->name = NULL;
+                               free(c2);
+                               c2 = NULL;
                        }
-
+                       
                        /* delete command */
                        free(c->name);
+                       c->name = NULL;
                        free(c);
+                       c = NULL;
+                       return ERROR_OK;
                }
-
+               
                /* remember the last command for unlinking */
                p = c;
+               c = c->next;
        }
 
        return ERROR_OK;
@@ -433,7 +453,7 @@ int command_run_line(command_context_t *context, char *line)
                retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
                if (retcode == JIM_OK)
                {
-                       retcode = Jim_Eval_Named(interp, line, __FILE__, __LINE__ );
+                       retcode = Jim_Eval_Named(interp, line, __THIS__FILE__, __LINE__ );
 
                        Jim_DeleteAssocData(interp, "retval");
                }
@@ -639,7 +659,7 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        log_add_callback(tcl_output, tclOutput);
 
-       retcode = Jim_Eval_Named(interp, str, __FILE__, __LINE__ );
+       retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__ );
 
        log_remove_callback(tcl_output, tclOutput);
 
@@ -653,7 +673,7 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 command_context_t* command_init()
 {
        command_context_t* context = malloc(sizeof(command_context_t));
-       extern unsigned const char startup_tcl[];
+       extern const char startup_tcl[];
 
        context->mode = COMMAND_EXEC;
        context->commands = NULL;
@@ -795,3 +815,16 @@ void register_jim(struct command_context_s *cmd_ctx, const char *name, int (*cmd
        Jim_ListAppendElement(interp, cmd_entry, Jim_NewStringObj(interp, help, -1));
        Jim_ListAppendElement(interp, helptext, cmd_entry);
 }
+
+
+/* return global variable long value or 0 upon failure */
+long jim_global_long(const char *variable)
+{
+       Jim_Obj *objPtr=Jim_GetGlobalVariableStr(interp, variable, JIM_ERRMSG);
+       long t;
+       if (Jim_GetLong(interp, objPtr, &t)==JIM_OK)
+       {
+               return t;
+       }
+       return 0;
+}