Fix zombie job on failed redirection in exec_job

Closes #5346.
This commit is contained in:
Mahmoud Al-Qudsi 2018-11-18 17:14:08 -06:00
parent a8ce7bad7b
commit d0085cae3c
3 changed files with 14 additions and 13 deletions

View file

@ -990,16 +990,16 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr<
return true; return true;
} }
void exec_job(parser_t &parser, shared_ptr<job_t> j) { bool exec_job(parser_t &parser, shared_ptr<job_t> j) {
assert(j && "null job_t passed to exec_job!"); assert(j && "null job_t passed to exec_job!");
// Set to true if something goes wrong while exec:ing the job, in which case the cleanup code // Set to true if something goes wrong while executing the job, in which case the cleanup
// will kick in. // code will kick in.
bool exec_error = false; bool exec_error = false;
// If fish was invoked with -n or --no-execute, then no_exec will be set and we do nothing. // If fish was invoked with -n or --no-execute, then no_exec will be set and we do nothing.
if (no_exec) { if (no_exec) {
return; return true;
} }
const std::shared_ptr<job_t> parent_job = j->get_parent(); const std::shared_ptr<job_t> parent_job = j->get_parent();
@ -1059,7 +1059,7 @@ void exec_job(parser_t &parser, shared_ptr<job_t> j) {
// 3. The pipe that the next process should read from (courtesy of us) // 3. The pipe that the next process should read from (courtesy of us)
// //
autoclose_fd_t pipe_next_read; autoclose_fd_t pipe_next_read;
for (std::unique_ptr<process_t> &unique_p : j->processes) { for (const auto &unique_p : j->processes) {
autoclose_fd_t current_read = std::move(pipe_next_read); autoclose_fd_t current_read = std::move(pipe_next_read);
if (!exec_process_in_job(parser, unique_p.get(), j, std::move(current_read), if (!exec_process_in_job(parser, unique_p.get(), j, std::move(current_read),
&pipe_next_read, all_ios, stdout_read_limit)) { &pipe_next_read, all_ios, stdout_read_limit)) {
@ -1077,13 +1077,12 @@ void exec_job(parser_t &parser, shared_ptr<job_t> j) {
env_set_one(L"last_pid", ENV_GLOBAL, to_string(j->pgid)); env_set_one(L"last_pid", ENV_GLOBAL, to_string(j->pgid));
} }
if (!exec_error) { if (exec_error) {
j->continue_job(false); return false;
} else {
// Mark the errored job as not in the foreground. I can't fully justify whether this is the
// right place, but it prevents sanity_lose from complaining.
j->set_flag(job_flag_t::FOREGROUND, false);
} }
j->continue_job(false);
return true;
} }
static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, bool apply_exit_status, static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, bool apply_exit_status,

View file

@ -14,7 +14,7 @@
/// Execute the processes specified by \p j in the parser \p. /// Execute the processes specified by \p j in the parser \p.
class job_t; class job_t;
class parser_t; class parser_t;
void exec_job(parser_t &parser, std::shared_ptr<job_t> j); bool exec_job(parser_t &parser, std::shared_ptr<job_t> j);
/// Evaluate the expression cmd in a subshell, add the outputs into the list l. On return, the /// Evaluate the expression cmd in a subshell, add the outputs into the list l. On return, the
/// status flag as returned bu \c proc_gfet_last_status will not be changed. /// status flag as returned bu \c proc_gfet_last_status will not be changed.

View file

@ -1232,7 +1232,9 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t<g::job> jo
} }
// Actually execute the job. // Actually execute the job.
exec_job(*this->parser, job); if (!exec_job(*this->parser, job)) {
parser->job_remove(job.get());
}
// Only external commands require a new fishd barrier. // Only external commands require a new fishd barrier.
if (job_contained_external_command) { if (job_contained_external_command) {