gdb: generate the prefix name for prefix commands on demand

Previously, the prefixname field of struct cmd_list_element was manually
set for prefix commands.  This seems verbose and error prone as it
required every single call to functions adding prefix commands to
specify the prefix name while the same information can be easily
generated.

Historically, this was not possible as the prefix field was null for
many commands, but this was fixed in commit
3f4d92ebdf by Philippe Waroquiers, so
we can rely on the prefix field being set when generating the prefix
name.

This commit also fixes a use after free in this scenario:
* A command gets created via Python (using the gdb.Command class).
  The prefix name member is dynamically allocated.
* An alias to the new command is created. The alias's prefixname is set
  to point to the prefixname for the original command with a direct
  assignment.
* A new command with the same name as the Python command is created.
* The object for the original Python command gets freed and its
  prefixname gets freed as well.
* The alias is updated to point to the new command, but its prefixname
  is not updated so it keeps pointing to the freed one.

gdb/ChangeLog:

	* command.h (add_prefix_cmd): Remove the prefixname argument as
	it can now be generated automatically.  Update all callers.
	(add_basic_prefix_cmd): Ditto.
	(add_show_prefix_cmd): Ditto.
	(add_prefix_cmd_suppress_notification): Ditto.
	(add_abbrev_prefix_cmd): Ditto.
	* cli/cli-decode.c (add_prefix_cmd): Ditto.
	(add_basic_prefix_cmd): Ditto.
	(add_show_prefix_cmd): Ditto.
	(add_prefix_cmd_suppress_notification): Ditto.
	(add_prefix_cmd_suppress_notification): Ditto.
	(add_abbrev_prefix_cmd): Ditto.
	* cli/cli-decode.h (struct cmd_list_element): Replace the
	prefixname member variable with a method which generates the
	prefix name at runtime.  Update all code reading the prefix
	name to use the method, and remove all code setting it.
	* python/py-cmd.c (cmdpy_destroyer): Remove code to free the
	prefixname member as it's now a method.
	(cmdpy_function): Determine if the command is a prefix by
	looking at prefixlist, not prefixname.
This commit is contained in:
Marco Barisione 2021-05-12 11:19:22 +01:00
parent f0bbe8bab8
commit 2f822da535
69 changed files with 236 additions and 285 deletions

View file

@ -2352,10 +2352,10 @@ Show verbosity."), NULL,
add_basic_prefix_cmd ("history", class_support, _("\
Generic command for setting command history parameters."),
&sethistlist, "set history ", 0, &setlist);
&sethistlist, 0, &setlist);
add_show_prefix_cmd ("history", class_support, _("\
Generic command for showing command history parameters."),
&showhistlist, "show history ", 0, &showlist);
&showhistlist, 0, &showlist);
add_setshow_boolean_cmd ("expansion", no_class, &history_expansion_p, _("\
Set history expansion on command input."), _("\
@ -2367,7 +2367,7 @@ Without an argument, history expansion is enabled."),
add_prefix_cmd ("info", class_info, info_command, _("\
Generic command for showing things about the program being debugged."),
&infolist, "info ", 0, &cmdlist);
&infolist, 0, &cmdlist);
add_com_alias ("i", "info", class_info, 1);
add_com_alias ("inf", "info", class_info, 1);
@ -2376,7 +2376,7 @@ Generic command for showing things about the program being debugged."),
c = add_show_prefix_cmd ("show", class_info, _("\
Generic command for showing things about the debugger."),
&showlist, "show ", 0, &cmdlist);
&showlist, 0, &cmdlist);
/* Another way to get at the same thing. */
add_alias_cmd ("set", c, class_info, 0, &infolist);
@ -2449,11 +2449,11 @@ the previous command number shown."),
add_basic_prefix_cmd ("debug", no_class,
_("Generic command for setting gdb debugging flags."),
&setdebuglist, "set debug ", 0, &setlist);
&setdebuglist, 0, &setlist);
add_show_prefix_cmd ("debug", no_class,
_("Generic command for showing gdb debugging flags."),
&showdebuglist, "show debug ", 0, &showlist);
&showdebuglist, 0, &showlist);
c = add_com ("shell", class_support, shell_command, _("\
Execute the rest of the line as a shell command.\n\

View file

@ -318,7 +318,6 @@ add_alias_cmd (const char *name, cmd_list_element *old,
c->func = old->func;
c->function = old->function;
c->prefixlist = old->prefixlist;
c->prefixname = old->prefixname;
c->allow_unknown = old->allow_unknown;
c->abbrev_flag = abbrev_flag;
c->cmd_pointer = old;
@ -383,13 +382,11 @@ struct cmd_list_element *
add_prefix_cmd (const char *name, enum command_class theclass,
cmd_const_cfunc_ftype *fun,
const char *doc, struct cmd_list_element **prefixlist,
const char *prefixname, int allow_unknown,
struct cmd_list_element **list)
int allow_unknown, struct cmd_list_element **list)
{
struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list);
c->prefixlist = prefixlist;
c->prefixname = prefixname;
c->allow_unknown = allow_unknown;
/* Now that prefix command C is defined, we need to set the prefix field
@ -409,7 +406,8 @@ do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
while (c->cmd_pointer != nullptr)
c = c->cmd_pointer;
help_list (*c->prefixlist, c->prefixname, all_commands, gdb_stdout);
help_list (*c->prefixlist, c->prefixname ().c_str (),
all_commands, gdb_stdout);
}
/* See command.h. */
@ -417,11 +415,10 @@ do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
struct cmd_list_element *
add_basic_prefix_cmd (const char *name, enum command_class theclass,
const char *doc, struct cmd_list_element **prefixlist,
const char *prefixname, int allow_unknown,
struct cmd_list_element **list)
int allow_unknown, struct cmd_list_element **list)
{
struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr,
doc, prefixlist, prefixname,
doc, prefixlist,
allow_unknown, list);
set_cmd_sfunc (cmd, do_prefix_cmd);
return cmd;
@ -441,11 +438,10 @@ do_show_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
struct cmd_list_element *
add_show_prefix_cmd (const char *name, enum command_class theclass,
const char *doc, struct cmd_list_element **prefixlist,
const char *prefixname, int allow_unknown,
struct cmd_list_element **list)
int allow_unknown, struct cmd_list_element **list)
{
struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr,
doc, prefixlist, prefixname,
doc, prefixlist,
allow_unknown, list);
set_cmd_sfunc (cmd, do_show_prefix_cmd);
return cmd;
@ -459,13 +455,12 @@ add_prefix_cmd_suppress_notification
(const char *name, enum command_class theclass,
cmd_const_cfunc_ftype *fun,
const char *doc, struct cmd_list_element **prefixlist,
const char *prefixname, int allow_unknown,
struct cmd_list_element **list,
int allow_unknown, struct cmd_list_element **list,
int *suppress_notification)
{
struct cmd_list_element *element
= add_prefix_cmd (name, theclass, fun, doc, prefixlist,
prefixname, allow_unknown, list);
allow_unknown, list);
element->suppress_notification = suppress_notification;
return element;
}
@ -476,13 +471,11 @@ struct cmd_list_element *
add_abbrev_prefix_cmd (const char *name, enum command_class theclass,
cmd_const_cfunc_ftype *fun, const char *doc,
struct cmd_list_element **prefixlist,
const char *prefixname,
int allow_unknown, struct cmd_list_element **list)
{
struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list);
c->prefixlist = prefixlist;
c->prefixname = prefixname;
c->allow_unknown = allow_unknown;
c->abbrev_flag = 1;
return c;
@ -1034,10 +1027,11 @@ add_com_suppress_notification (const char *name, enum command_class theclass,
static void
fput_command_name_styled (struct cmd_list_element *c, struct ui_file *stream)
{
const char *prefixname
= c->prefix == nullptr ? "" : c->prefix->prefixname;
std::string prefixname
= c->prefix == nullptr ? "" : c->prefix->prefixname ();
fprintf_styled (stream, title_style.style (), "%s%s", prefixname, c->name);
fprintf_styled (stream, title_style.style (), "%s%s",
prefixname.c_str (), c->name);
}
/* Print the definition of alias C using title style for alias
@ -1192,7 +1186,8 @@ apropos_cmd (struct ui_file *stream,
{
/* Recursively call ourselves on the subcommand list,
passing the right prefix in. */
apropos_cmd (stream, *c->prefixlist, verbose, regex, c->prefixname);
apropos_cmd (stream, *c->prefixlist, verbose, regex,
c->prefixname ().c_str ());
}
}
}
@ -1258,7 +1253,8 @@ help_cmd (const char *command, struct ui_file *stream)
/* If this is a prefix command, print it's subcommands. */
if (c->prefixlist)
help_list (*c->prefixlist, c->prefixname, all_commands, stream);
help_list (*c->prefixlist, c->prefixname ().c_str (),
all_commands, stream);
/* If this is a class name, print all of the commands in the class. */
if (c->func == NULL)
@ -1812,7 +1808,8 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
values. */
int local_allow_unknown = (last_list ? last_list->allow_unknown :
allow_unknown);
const char *local_cmdtype = last_list ? last_list->prefixname : cmdtype;
std::string local_cmdtype
= last_list ? last_list->prefixname () : cmdtype;
struct cmd_list_element *local_list =
(last_list ? *(last_list->prefixlist) : list);
@ -1852,8 +1849,8 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
break;
}
}
error (_("Ambiguous %scommand \"%s\": %s."), local_cmdtype,
*line, ambbuf);
error (_("Ambiguous %scommand \"%s\": %s."),
local_cmdtype.c_str (), *line, ambbuf);
}
}
else
@ -1867,7 +1864,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
(*line)++;
if (c->prefixlist && **line && !c->allow_unknown)
undef_cmd_error (c->prefixname, *line);
undef_cmd_error (c->prefixname ().c_str (), *line);
/* Seems to be what he wants. Return it. */
return c;
@ -1940,7 +1937,7 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list)
/* Join command prefix (if any) and the command name. */
std::string tmp_cmd_str;
if (cmd->prefix != nullptr)
tmp_cmd_str += std::string (cmd->prefix->prefixname);
tmp_cmd_str += cmd->prefix->prefixname ();
tmp_cmd_str += std::string (cmd->name);
/* Display the appropriate first line, this warns that the thing the user
@ -1950,7 +1947,7 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list)
/* Join the alias prefix (if any) and the alias name. */
std::string tmp_alias_str;
if (alias->prefix != nullptr)
tmp_alias_str += std::string (alias->prefix->prefixname);
tmp_alias_str += alias->prefix->prefixname ();
tmp_alias_str += std::string (alias->name);
if (cmd->cmd_deprecated)

View file

@ -71,6 +71,25 @@ struct cmd_list_element
DISABLE_COPY_AND_ASSIGN (cmd_list_element);
/* For prefix commands, return a string containing prefix commands to
get here: this one plus any others needed to get to it. Ends in a
space. It is used before the word "command" in describing the
commands reached through this prefix.
For non-prefix commands, an empty string is returned. */
std::string prefixname ()
{
if (prefixlist == nullptr)
/* Not a prefix command. */
return "";
std::string prefixname;
if (prefix != nullptr)
prefixname = prefix->prefixname ();
prefixname += name;
prefixname += " ";
return prefixname;
}
/* Points to next command in this list. */
struct cmd_list_element *next = nullptr;
@ -186,13 +205,6 @@ struct cmd_list_element
of the variable containing the list of subcommands. */
struct cmd_list_element **prefixlist = nullptr;
/* For prefix commands only:
String containing prefix commands to get here: this one
plus any others needed to get to it. Should end in a space.
It is used before the word "command" in describing the
commands reached through this prefix. */
const char *prefixname = nullptr;
/* The prefix command of this command. */
struct cmd_list_element *prefix = nullptr;

View file

@ -572,12 +572,12 @@ _initialize_cli_dump ()
add_basic_prefix_cmd ("dump", class_vars,
_("Dump target code/data to a local file."),
&dump_cmdlist, "dump ",
&dump_cmdlist,
0/*allow-unknown*/,
&cmdlist);
add_basic_prefix_cmd ("append", class_vars,
_("Append target code/data to a local file."),
&append_cmdlist, "append ",
&append_cmdlist,
0/*allow-unknown*/,
&cmdlist);
@ -593,37 +593,37 @@ the specified FILE in raw target ordered bytes.");
add_basic_prefix_cmd ("srec", all_commands,
_("Write target code/data to an srec file."),
&srec_cmdlist, "dump srec ",
&srec_cmdlist,
0 /*allow-unknown*/,
&dump_cmdlist);
add_basic_prefix_cmd ("ihex", all_commands,
_("Write target code/data to an intel hex file."),
&ihex_cmdlist, "dump ihex ",
&ihex_cmdlist,
0 /*allow-unknown*/,
&dump_cmdlist);
add_basic_prefix_cmd ("verilog", all_commands,
_("Write target code/data to a verilog hex file."),
&verilog_cmdlist, "dump verilog ",
&verilog_cmdlist,
0 /*allow-unknown*/,
&dump_cmdlist);
add_basic_prefix_cmd ("tekhex", all_commands,
_("Write target code/data to a tekhex file."),
&tekhex_cmdlist, "dump tekhex ",
&tekhex_cmdlist,
0 /*allow-unknown*/,
&dump_cmdlist);
add_basic_prefix_cmd ("binary", all_commands,
_("Write target code/data to a raw binary file."),
&binary_dump_cmdlist, "dump binary ",
&binary_dump_cmdlist,
0 /*allow-unknown*/,
&dump_cmdlist);
add_basic_prefix_cmd ("binary", all_commands,
_("Append target code/data to a raw binary file."),
&binary_append_cmdlist, "append binary ",
&binary_append_cmdlist,
0 /*allow-unknown*/,
&append_cmdlist);

View file

@ -173,10 +173,10 @@ _initialize_cli_logging ()
add_basic_prefix_cmd ("logging", class_support,
_("Set logging options."), &set_logging_cmdlist,
"set logging ", 0, &setlist);
0, &setlist);
add_show_prefix_cmd ("logging", class_support,
_("Show logging options."), &show_logging_cmdlist,
"show logging ", 0, &showlist);
0, &showlist);
add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite, _("\
Set whether logging overwrites or appends to the log file."), _("\
Show whether logging overwrites or appends to the log file."), _("\

View file

@ -1472,7 +1472,6 @@ do_define_command (const char *comname, int from_tty,
{
struct cmd_list_element **c_prefixlist
= c == nullptr ? nullptr : c->prefixlist;
const char *c_prefixname = c == nullptr ? nullptr : c->prefixname;
newc = add_cmd (comname, class_user, user_defined_command,
(c != nullptr && c->theclass == class_user)
@ -1484,7 +1483,6 @@ do_define_command (const char *comname, int from_tty,
if (c_prefixlist != nullptr)
{
newc->prefixlist = c_prefixlist;
newc->prefixname = c_prefixname;
/* allow_unknown: see explanation in equivalent logic in
define_prefix_command (). */
newc->allow_unknown = newc->user_commands.get () != nullptr;
@ -1615,7 +1613,6 @@ define_prefix_command (const char *comname, int from_tty)
command. */
c->prefixlist = new struct cmd_list_element*;
*(c->prefixlist) = nullptr;
c->prefixname = xstrprintf ("%s ", comfull);
/* If the prefix command C is not a command, then it must be followed
by known subcommands. Otherwise, if C is also a normal command,
it can be followed by C args that must not cause a 'subcommand'
@ -1681,11 +1678,11 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
if (c->prefixlist != NULL)
{
const char *prefixname = c->prefixname;
const std::string prefixname = c->prefixname ();
for (c = *c->prefixlist; c != NULL; c = c->next)
if (c->theclass == class_user || c->prefixlist != NULL)
show_user_1 (c, prefixname, c->name, gdb_stdout);
show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout);
}
}

View file

@ -747,7 +747,8 @@ cmd_show_list (struct cmd_list_element *list, int from_tty)
if (list->prefixlist && list->cmd_pointer == nullptr)
{
ui_out_emit_tuple optionlist_emitter (uiout, "optionlist");
const char *new_prefix = strstr (list->prefixname, "show ") + 5;
std::string prefixname = list->prefixname ();
const char *new_prefix = strstr (prefixname.c_str (), "show ") + 5;
if (uiout->is_mi_like_p ())
uiout->field_string ("prefix", new_prefix);
@ -757,13 +758,14 @@ cmd_show_list (struct cmd_list_element *list, int from_tty)
{
ui_out_emit_tuple option_emitter (uiout, "option");
{
/* If we find a prefix, output it (with "show " skipped). */
const char *prefixname
= (list->prefix == nullptr ? ""
: strstr (list->prefix->prefixname, "show ") + 5);
uiout->text (prefixname);
}
if (list->prefix != nullptr)
{
/* If we find a prefix, output it (with "show " skipped). */
std::string prefixname = list->prefix->prefixname ();
prefixname = (list->prefix->prefixlist == nullptr ? ""
: strstr (prefixname.c_str (), "show ") + 5);
uiout->text (prefixname.c_str ());
}
uiout->field_string ("name", list->name);
uiout->text (": ");
if (list->type == show_cmd)

View file

@ -225,13 +225,10 @@ cli_style_option::add_setshow_commands (enum command_class theclass,
struct cmd_list_element **show_list,
bool skip_intensity)
{
m_set_prefix = std::string ("set style ") + m_name + " ";
m_show_prefix = std::string ("show style ") + m_name + " ";
add_basic_prefix_cmd (m_name, no_class, prefix_doc, &m_set_list,
m_set_prefix.c_str (), 0, set_list);
0, set_list);
add_show_prefix_cmd (m_name, no_class, prefix_doc, &m_show_list,
m_show_prefix.c_str (), 0, show_list);
0, show_list);
add_setshow_enum_cmd ("foreground", theclass, cli_colors,
&m_foreground,
@ -297,11 +294,11 @@ _initialize_cli_style ()
add_basic_prefix_cmd ("style", no_class, _("\
Style-specific settings.\n\
Configure various style-related variables, such as colors"),
&style_set_list, "set style ", 0, &setlist);
&style_set_list, 0, &setlist);
add_show_prefix_cmd ("style", no_class, _("\
Style-specific settings.\n\
Configure various style-related variables, such as colors"),
&style_show_list, "show style ", 0, &showlist);
&style_show_list, 0, &showlist);
add_setshow_boolean_cmd ("enabled", no_class, &cli_styling, _("\
Set whether CLI styling is enabled."), _("\

View file

@ -72,9 +72,6 @@ private:
/* The intensity. */
const char *m_intensity;
/* Storage for prefixes needed when registering the commands. */
std::string m_show_prefix;
std::string m_set_prefix;
/* Storage for command lists needed when registering
subcommands. */
struct cmd_list_element *m_set_list = nullptr;