From 8e4010b263ec53478a1b8898f9146e4e4bcefdc0 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sat, 13 Apr 2019 13:05:04 -0500 Subject: [PATCH] Make `eval` override previous status Closes #5692 (again). --- src/builtin_eval.cpp | 11 +++++++---- src/exec.cpp | 11 ++++++++--- src/exec.h | 3 +++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/builtin_eval.cpp b/src/builtin_eval.cpp index 680edc83c..660559e0d 100644 --- a/src/builtin_eval.cpp +++ b/src/builtin_eval.cpp @@ -9,6 +9,7 @@ #include "builtin.h" #include "common.h" +#include "exec.h" #include "fallback.h" // IWYU pragma: keep #include "io.h" #include "parser.h" @@ -16,8 +17,6 @@ #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep -class parser_t; - /// Implementation of eval builtin. int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) { int argc = builtin_count_args(argv); @@ -28,16 +27,20 @@ int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) { new_cmd += argv[i]; } - // debug(1, "new_cmd: %ls", new_cmd.c_str()); - + size_t cached_exec_count = exec_get_exec_count(); int status = STATUS_CMD_OK; if (argc > 1) { if (parser.eval(std::move(new_cmd), *streams.io_chain, block_type_t::TOP) != 0) { // This indicates a parse error; nothing actually got executed. status = STATUS_CMD_ERROR; + } else if (cached_exec_count == exec_get_exec_count()) { + // Issue #5692, in particular, to catch `eval ""`, `eval "begin; end;"`, etc. + // where we have an argument but nothing is executed. + status = STATUS_CMD_OK; } else { status = proc_get_last_status(); } } + return status; } diff --git a/src/exec.cpp b/src/exec.cpp index d9f83a506..a17291cda 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -864,6 +864,14 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr return true; } +// The number of overall "command" executions, for whatever definition of "command". Its delta +// is used to determine the number of recursive `exec_process_in_job()` invocations. +static size_t exec_count = 0; + +size_t exec_get_exec_count() { + return exec_count; +} + /// Executes a process \p in job \j, using the pipes \p pipes (which may have invalid fds if this is /// the first or last process). /// \p deferred_pipes represents the pipes from our deferred process; if set ensure they get closed @@ -926,9 +934,6 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< } } - // The number of overall "command" executions, for whatever definition of "command". Its delta - // is used to determine the number of recursive `exec_process_in_job()` invocations. - static size_t exec_count = 0; if (p->type != process_type_t::block_node) { // An simple `begin ... end` should not be considered an execution of a command. exec_count++; diff --git a/src/exec.h b/src/exec.h index 12c5d9051..fe776db8a 100644 --- a/src/exec.h +++ b/src/exec.h @@ -31,6 +31,9 @@ int exec_subshell(const wcstring &cmd, parser_t &parser, bool preserve_exit_stat /// Loops over close until the syscall was run without being interrupted. void exec_close(int fd); +/// Returns the number of executions. May roll over. +size_t exec_get_exec_count(); + /// Gets the interpreter for a given command. char *get_interpreter(const char *command, char *interpreter, size_t buff_size);