Stop expanding globs in command position when performing error checking

Before running a command, or before importing a command from bash history,
we perform error checking. As part of error checking we expand commands
including variables and globs. If the glob is very large, like `/**`, then
we could hang expanding it.

One fix would be to limit the amount of expansion from the glob, but
instead let's just not expand command globs when performing error checking.

Fixes #7407
This commit is contained in:
ridiculousfish 2020-12-20 13:36:12 -08:00
parent a8080e8e6f
commit e43913a547
5 changed files with 16 additions and 7 deletions

View File

@ -1176,16 +1176,20 @@ bool expand_one(wcstring &string, expand_flags_t flags, const operation_context_
expand_result_t expand_to_command_and_args(const wcstring &instr, const operation_context_t &ctx,
wcstring *out_cmd, wcstring_list_t *out_args,
parse_error_list_t *errors) {
parse_error_list_t *errors, bool skip_wildcards) {
// Fast path.
if (expand_is_clean(instr)) {
*out_cmd = instr;
return expand_result_t::ok;
}
expand_flags_t eflags{expand_flag::skip_cmdsubst};
if (skip_wildcards) {
eflags.set(expand_flag::skip_wildcards);
}
completion_list_t completions;
expand_result_t expand_err =
expand_string(instr, &completions, {expand_flag::skip_cmdsubst}, ctx, errors);
expand_result_t expand_err = expand_string(instr, &completions, eflags, ctx, errors);
if (expand_err == expand_result_t::ok) {
// The first completion is the command, any remaning are arguments.
bool first = true;

View File

@ -182,10 +182,12 @@ bool expand_one(wcstring &string, expand_flags_t flags, const operation_context_
/// If the expansion resulted in no or an empty command, the command will be an empty string. Note
/// that API does not distinguish between expansion resulting in an empty command (''), and
/// expansion resulting in no command (e.g. unset variable).
// \return an expand error.
/// If \p skip_wildcards is true, then do not do wildcard expansion
/// \return an expand error.
expand_result_t expand_to_command_and_args(const wcstring &instr, const operation_context_t &ctx,
wcstring *out_cmd, wcstring_list_t *out_args,
parse_error_list_t *errors = nullptr);
parse_error_list_t *errors = nullptr,
bool skip_wildcards = false);
/// Convert the variable value to a human readable form, i.e. escape things, handle arrays, etc.
/// Suitable for pretty-printing.

View File

@ -4374,7 +4374,8 @@ void history_tests_t::test_history_formats() {
} else {
// The results are in the reverse order that they appear in the bash history file.
// We don't expect whitespace to be elided (#4908: except for leading/trailing whitespace)
const wchar_t *expected[] = {L"sleep 123",
const wchar_t *expected[] = {L"/** # see issue 7407",
L"sleep 123",
L"a && echo valid construct",
L"final line",
L"echo supsup",

View File

@ -1136,7 +1136,8 @@ static bool detect_errors_in_decorated_statement(const wcstring &buff_src,
wcstring command;
// Check that we can expand the command.
if (expand_to_command_and_args(unexp_command, operation_context_t::empty(), &command,
nullptr, parse_errors) == expand_result_t::error) {
nullptr, parse_errors,
true /* skip wildcards */) == expand_result_t::error) {
errored = true;
parse_error_offset_source_start(parse_errors, source_start);
}

View File

@ -17,3 +17,4 @@ a && echo valid construct
(( 1 = 2 )) && echo double parens not allowed
posix_cmd_sub $(is not supported)
sleep 123
/** # see issue 7407