From 311378bc3b871b199f439152c39debb7ec02e21c Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Tue, 16 Sep 2025 17:02:01 +0100 Subject: [PATCH] gdb: fix --args handling when inferior argument have dash After the commit: commit e5e76451fa82e0bc00599af96382b361c3d6ac32 Date: Fri Oct 22 07:19:29 2021 +0000 gdb/gdbserver: add a '--no-escape-args' command line option Inferior argument handling on the GDB command line was broken: $ gdb --args /bin/ls --foo ./gdb/gdb: unrecognized option '--foo' ./gdb/gdb: `--args' specified but no program specified Before the above patch the definition of the '--args' argument in the long_options array (in captured_main_1) was such that the getopt_long_only call would directly set the 'set_args' variable to true if '--args' was seen. This meant that, immediately after the getopt_long_only call, we could inspect set_args and break out of the argument processing loop if needed. After the above patch '--args' (and the new '--no-escape-args') no longer set set_args directly via the getopt_long_only call. Instead the getopt_long_only call returns an OPT_* enum value, which we then use in the following switch statement in order to set the set_args variable. What this means is that, immediately after the getopt_long_only call, set_args no longer (immediately) indicates if --args was seen. After the switch statement, when set_args has been updated, we go around the argument processing loop again and call getopt_long_only once more. This extra getopt_long_only call will, if it finds another argument that starts with a dash, update the global optind to point to this option. At this point things have gone wrong, GDB has now lost track of the argument containing the program name the user wanted us to start. This leads to GDB exiting with the above error. The solution is to move the check of set_args to either before the getopt_long_only call, or to after the switch statement. I chose to move it earlier as this keeps all the loop exiting checks near the beginning. I've added more tests that cover this issue. Approved-By: Luis Machado Tested-By: Luis Machado --- gdb/main.c | 7 ++++++- gdb/testsuite/gdb.base/args.exp | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gdb/main.c b/gdb/main.c index 04c33638bec..f3049600a06 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -866,9 +866,14 @@ captured_main_1 (struct captured_main_args *context) { int option_index; + /* If the previous argument was --args or --no-escape-args, then + stop argument processing. */ + if (set_args != NO_ARGS) + break; + c = getopt_long_only (argc, argv, "", long_options, &option_index); - if (c == EOF || set_args != NO_ARGS) + if (c == EOF) break; /* Long option that takes an argument. */ diff --git a/gdb/testsuite/gdb.base/args.exp b/gdb/testsuite/gdb.base/args.exp index 573543cc1f8..39300594773 100644 --- a/gdb/testsuite/gdb.base/args.exp +++ b/gdb/testsuite/gdb.base/args.exp @@ -186,6 +186,19 @@ proc run_all_tests {} { set ::env(TEST) "ABCD" args_test "shell variable" {{$TEST}} {\\$TEST} {{ABCD}} } + + # At one point we had a bug where, if the last inferior argument, + # appearing after --args, looked like an option GDB might be able + # to process, e.g. started with a dash, then GDB would try to + # process it. This would leave GDB in a broken state, and so GDB + # would fail to start. A example of a failing GDB command line: + # $ gdb --args /bin/ls --all + foreach_with_prefix flag { args no-escape-args } { + args_test "with trailing GDB flag" [list "--${flag}"] + } + args_test "with trailing GDB option and value" [list "--ex" "start"] + args_test "with trailing double dash option" [list "--foo"] + args_test "with trailing single dash option" [list "-foo"] } run_all_tests -- 2.47.3