This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
[python] fix command deletion bug
- From: Tom Tromey <tromey at redhat dot com>
- To: Project Archer <archer at sourceware dot org>
- Date: Mon, 10 Nov 2008 07:14:49 -0700
- Subject: [python] fix command deletion bug
- Reply-to: tromey at redhat dot com
This fixes a bug that can cause gdb to crash. It was reported a while
ago as gdb PR 1815.
The bug is that an alias points to its target command. So, if the
target command is redefined, then the alias has a dangling pointer;
executing the alias can cause a crash.
This patch fixes the problem by keeping back-links from targets to
aliases.
I wanted to fix this for the Python branch because I've been playing
with a Python rewrite of "backtrace", which has aliases.
I'll submit this upstream soon.
Tom
2008-11-10 Tom Tromey <tromey@redhat.com>
PR gdb/1815:
* cli/cli-decode.c (delete_cmd): Forward declare.
(delete_cmd): Now static. Change return type. Remove command
from alias chain.
(add_cmd): Initialize new fields. Update cmd_pointer on all
aliases.
(add_alias_cmd): Put command on alias chain.
* command.h (delete_cmd): Don't declare.
* cli/cli-decode.h (delete_cmd): Don't declare.
(struct cmd_list_element) <aliases, alias_chain>: New fields.
2008-11-10 Tom Tromey <tromey@redhat.com>
* gdb.base/commands.exp (redefine_backtrace_test): New proc.
Call it.
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index b897124..56964e4 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -37,6 +37,9 @@
static void undef_cmd_error (char *, char *);
+static struct cmd_list_element *delete_cmd (char *name,
+ struct cmd_list_element **list);
+
static struct cmd_list_element *find_cmd (char *command,
int len,
struct cmd_list_element *clist,
@@ -155,9 +158,13 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
{
struct cmd_list_element *c
= (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element));
- struct cmd_list_element *p;
+ struct cmd_list_element *p, *iter;
- delete_cmd (name, list);
+ /* Turn each alias of the old command into an alias of the new
+ command. */
+ c->aliases = delete_cmd (name, list);
+ for (iter = c->aliases; iter; iter = iter->alias_chain)
+ iter->cmd_pointer = c;
if (*list == NULL || strcmp ((*list)->name, name) >= 0)
{
@@ -200,6 +207,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
c->hookee_pre = NULL;
c->hookee_post = NULL;
c->cmd_pointer = NULL;
+ c->alias_chain = NULL;
return c;
}
@@ -254,6 +262,8 @@ add_alias_cmd (char *name, char *oldname, enum command_class class,
c->allow_unknown = old->allow_unknown;
c->abbrev_flag = abbrev_flag;
c->cmd_pointer = old;
+ c->alias_chain = old->aliases;
+ old->aliases = c;
return c;
}
@@ -618,11 +628,12 @@ add_setshow_zinteger_cmd (char *name, enum command_class class,
/* Remove the command named NAME from the command list. */
-void
+static struct cmd_list_element *
delete_cmd (char *name, struct cmd_list_element **list)
{
struct cmd_list_element *iter;
struct cmd_list_element **previous_chain_ptr;
+ struct cmd_list_element *aliases = NULL;
previous_chain_ptr = list;
@@ -637,16 +648,36 @@ delete_cmd (char *name, struct cmd_list_element **list)
if (iter->hookee_post)
iter->hookee_post->hook_post = 0;
- /* Update the link. Note that we don't change
- previous_chain_ptr; next time through the loop this must
- stay the same. */
+ /* Update the link. */
*previous_chain_ptr = iter->next;
+ aliases = iter->aliases;
+
+ /* If this command was an alias, remove it from the list of
+ aliases. */
+ if (iter->cmd_pointer)
+ {
+ struct cmd_list_element **prevp = &iter->cmd_pointer->aliases;
+ struct cmd_list_element *a = *prevp;
+
+ while (a != iter)
+ {
+ prevp = &a->alias_chain;
+ a = *prevp;
+ }
+ *prevp = iter->alias_chain;
+ }
+
xfree (iter);
+
+ /* We won't see another command with the same name. */
+ break;
}
else
previous_chain_ptr = &iter->next;
}
+
+ return aliases;
}
/* Shorthands to the commands above. */
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 2888398..c9da41c 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -202,6 +202,13 @@ struct cmd_list_element
/* Pointer to command that is aliased by this one, so the
aliased command can be located in case it has been hooked. */
struct cmd_list_element *cmd_pointer;
+
+ /* Start of a linked list of all aliases of this command. */
+ struct cmd_list_element *aliases;
+
+ /* Link pointer for aliases on an alias list. */
+ struct cmd_list_element *alias_chain;
+
};
/* API to the manipulation of command lists. */
@@ -296,8 +303,6 @@ extern char **complete_on_cmdlist (struct cmd_list_element *, char *, char *);
extern char **complete_on_enum (const char *enumlist[], char *, char *);
-extern void delete_cmd (char *, struct cmd_list_element **);
-
extern void help_cmd_list (struct cmd_list_element *, enum command_class,
char *, int, struct ui_file *);
diff --git a/gdb/command.h b/gdb/command.h
index a82ce3a..add3a52 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -194,8 +194,6 @@ extern char **complete_on_cmdlist (struct cmd_list_element *, char *, char *);
extern char **complete_on_enum (const char *enumlist[], char *, char *);
-extern void delete_cmd (char *, struct cmd_list_element **);
-
extern void help_cmd (char *, struct ui_file *);
extern void help_list (struct cmd_list_element *, char *,
diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp
index 301b995..41d5bec 100644
--- a/gdb/testsuite/gdb.base/commands.exp
+++ b/gdb/testsuite/gdb.base/commands.exp
@@ -692,6 +692,34 @@ proc if_commands_test {} {
}
}
+proc redefine_backtrace_test {} {
+ global gdb_prompt
+
+ send_gdb "define backtrace\n"
+ gdb_expect {
+ -re "Really redefine built-in.*$" {
+ send_gdb "y\n"
+ }
+
+ -re "End with" {
+ pass "define backtrace in redefine_backtrace_test"
+ }
+ default {
+ fail "(timeout or eof) define backtrace in redefine_backtrace_test"
+ }
+ }
+ gdb_test "echo hibob\\n\nend" \
+ "" \
+ "enter commands in redefine_backtrace_test"
+
+ gdb_test "backtrace" \
+ "hibob" \
+ "execute backtrace command in redefine_backtrace_test"
+ gdb_test "bt" \
+ "hibob" \
+ "execute bt command in redefine_backtrace_test"
+}
+
gdbvar_simple_if_test
gdbvar_simple_while_test
gdbvar_complex_if_while_test
@@ -710,3 +738,5 @@ temporary_breakpoint_commands
stray_arg0_test
recursive_source_test
if_commands_test
+# This one should come last, as it redefines "backtrace".
+redefine_backtrace_test