gdb/python: check for invalid prefixes in Command/Parameter creation
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gdb_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gdb_check--master-arm |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 |
success
|
Test passed
|
Commit Message
The manual for gdb.Parameter says:
If NAME consists of multiple words, and no prefix parameter group
can be found, an exception is raised.
This makes sense; we cannot create a parameter within a prefix group,
if the prefix doesn't exist. And this almost works, so:
(gdb) python gdb.Parameter("xxx foo", gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)
Python Exception <class 'RuntimeError'>: Could not find command prefix xxx.
Error occurred in Python: Could not find command prefix xxx.
The prefix 'xxx' doesn't exist, and we get an error. But, if we try
multiple levels of prefix:
(gdb) python gdb.Parameter("print xxx foo", gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)
This completes without error, however, we didn't get what we were
maybe expecting:
(gdb) show print xxx foo
Undefined show print command: "xxx foo". Try "help show print".
But we did get:
(gdb) show print foo
The current value of 'print foo' is "off".
GDB stopped scanning the prefix string at the unknown 'xxx', and just
created the parameter there. I don't think this makes sense, nor is
it inline with the manual.
An identical problem exists with gdb.Command creation; GDB stops
parsing the prefix at the first unknown prefix, and just creates the
command there. The manual for gdb.Command says:
NAME is the name of the command. If NAME consists of multiple
words, then the initial words are looked for as prefix commands.
In this case, if one of the prefix commands does not exist, an
exception is raised.
So again, the correct action is, I believe, to raise an exception.
The problem is in gdbpy_parse_command_name (python/py-cmd.c), GDB
calls lookup_cmd_1 to look through the prefix string and return the
last prefix group. If the very first prefix word is invalid then
lookup_cmd_1 returns NULL, and this case is handled. However, if
there is a valid prefix, followed by an invalid prefix, then
lookup_cmd_1 will return a pointer to the last valid prefix list, and
will update the input argument to point to the start of the invalid
prefix word. This final case, where the input is left pointing to an
unknown prefix, was previously not handled.
I've fixed gdbpy_parse_command_name, and added tests for command and
parameter creation to cover this case.
---
gdb/python/py-cmd.c | 2 +-
gdb/testsuite/gdb.python/py-cmd.exp | 27 ++++++++++++++++
gdb/testsuite/gdb.python/py-parameter.exp | 38 +++++++++++++++++++++++
3 files changed, 66 insertions(+), 1 deletion(-)
base-commit: ea0498f46e440199907213d920b7964d4fc38dc5
Comments
>>>>> "Andrew" == Andrew Burgess <aburgess@redhat.com> writes:
Andrew> So again, the correct action is, I believe, to raise an exception.
Agreed.
The patch looks good to me. Thanks.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
@@ -385,7 +385,7 @@ gdbpy_parse_command_name (const char *name,
prefix_text2 = prefix_text.c_str ();
elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
- if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
+ if (elt == nullptr || elt == CMD_LIST_AMBIGUOUS || *prefix_text2 != '\0')
{
PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
prefix_text.c_str ());
@@ -328,4 +328,31 @@ proc_with_prefix test_command_redefining_itself {} {
"call command redefining itself 2"
}
+# Try to create commands using unknown prefixes and check GDB gives an
+# error. There's also a test in here for an ambiguous prefix, which
+# gives the same error.
+proc_with_prefix test_unknown_prefix {} {
+ clean_restart
+
+ gdb_test_no_output "python gdb.Command('foo1', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('foo cmd', gdb.COMMAND_NONE)"
+
+ foreach prefix { "xxx" "foo xxx" "foo1 xxx" } {
+ gdb_test "python gdb.Command('$prefix cmd', gdb.COMMAND_NONE)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
+
+ gdb_test_no_output "python gdb.Command('foo2', gdb.COMMAND_NONE, prefix=True)"
+
+ foreach prefix { "foo" "foo xxx" "foo1 xxx" "foo2 xxx" } {
+ gdb_test "python gdb.Command('$prefix cmd2', gdb.COMMAND_NONE)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
+}
+
test_command_redefining_itself
+test_unknown_prefix
@@ -669,6 +669,43 @@ proc_with_prefix test_ambiguous_parameter {} {
"Parameter .* is ambiguous.*Error occurred in Python.*"
gdb_test "python print(gdb.parameter('test-ambiguous-value-1a'))" \
"Could not find parameter.*Error occurred in Python.*"
+
+ # Create command prefixs 'set foo1' and 'show foo1'.
+ gdb_test_no_output "python gdb.Command('set foo1', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('show foo1', gdb.COMMAND_NONE, prefix=True)"
+
+ # Create a parameter under 'foo1', but use a truncated prefix. At
+ # this point though, the prefix is not ambiguous.
+ gdb_test_no_output "python gdb.Parameter('foo bar', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)"
+ gdb_test "python print(gdb.parameter('foo1 bar'))" "False"
+
+ # Create another prefix command, similar in name to the first.
+ gdb_test_no_output "python gdb.Command('set foo2', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('show foo2', gdb.COMMAND_NONE, prefix=True)"
+
+ # An attempt to create a parameter using an ambiguous prefix will give an error.
+ gdb_test "python gdb.Parameter('foo baz', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix foo\\." \
+ "Error occurred in Python: Could not find command prefix foo\\."]
+}
+
+# Check that creating a gdb.Parameter with an unknown command prefix results in an error.
+proc_with_prefix test_unknown_prefix {} {
+ gdb_test_multiline "create parameter" \
+ "python" "" \
+ "class UnknownPrefixParam(gdb.Parameter):" "" \
+ " def __init__ (self, name):" "" \
+ " super().__init__ (name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "end"
+
+ foreach prefix { "unknown-prefix" "style unknown-prefix" "style disassembler unknown-prefix"} {
+ gdb_test "python UnknownPrefixParam('$prefix new-param')" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
}
test_directories
@@ -685,5 +722,6 @@ test_integer_parameter
test_throwing_parameter
test_language
test_ambiguous_parameter
+test_unknown_prefix
rename py_param_test_maybe_no_output ""