1 // Provides the "linkage" between an ast and actual execution structures (job_t, etc.)
2 #include "config.h"  // IWYU pragma: keep
3 
4 #include "parse_execution.h"
5 
6 #include <errno.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <termios.h>
11 #include <unistd.h>
12 #include <wctype.h>
13 
14 #include <algorithm>
15 #include <cwchar>
16 #include <memory>
17 #include <string>
18 #include <type_traits>
19 #include <vector>
20 
21 #include "ast.h"
22 #include "builtin.h"
23 #include "builtin_function.h"
24 #include "common.h"
25 #include "complete.h"
26 #include "env.h"
27 #include "event.h"
28 #include "exec.h"
29 #include "expand.h"
30 #include "flog.h"
31 #include "function.h"
32 #include "io.h"
33 #include "job_group.h"
34 #include "maybe.h"
35 #include "parse_constants.h"
36 #include "parse_util.h"
37 #include "parser.h"
38 #include "path.h"
39 #include "proc.h"
40 #include "reader.h"
41 #include "timer.h"
42 #include "tokenizer.h"
43 #include "trace.h"
44 #include "util.h"
45 #include "wildcard.h"
46 #include "wutil.h"
47 
48 /// These are the specific statement types that support redirections.
type_is_redirectable_block(ast::type_t type)49 static constexpr bool type_is_redirectable_block(ast::type_t type) {
50     using t = ast::type_t;
51     return type == t::block_statement || type == t::if_statement || type == t::switch_statement;
52 }
53 
specific_statement_type_is_redirectable_block(const ast::node_t & node)54 static bool specific_statement_type_is_redirectable_block(const ast::node_t &node) {
55     return type_is_redirectable_block(node.type);
56 }
57 
58 /// Get the name of a redirectable block, for profiling purposes.
profiling_cmd_name_for_redirectable_block(const ast::node_t & node,const parsed_source_t & pstree)59 static wcstring profiling_cmd_name_for_redirectable_block(const ast::node_t &node,
60                                                           const parsed_source_t &pstree) {
61     using namespace ast;
62     assert(specific_statement_type_is_redirectable_block(node));
63 
64     auto source_range = node.try_source_range();
65     assert(source_range.has_value() && "No source range for block");
66 
67     size_t src_end = 0;
68     switch (node.type) {
69         case type_t::block_statement: {
70             const node_t *block_header = node.as<block_statement_t>()->header.get();
71             switch (block_header->type) {
72                 case type_t::for_header:
73                     src_end = block_header->as<for_header_t>()->semi_nl.source_range().start;
74                     break;
75 
76                 case type_t::while_header:
77                     src_end = block_header->as<while_header_t>()->condition.source_range().end();
78                     break;
79 
80                 case type_t::function_header:
81                     src_end = block_header->as<function_header_t>()->semi_nl.source_range().start;
82                     break;
83 
84                 case type_t::begin_header:
85                     src_end = block_header->as<begin_header_t>()->kw_begin.source_range().end();
86                     break;
87 
88                 default:
89                     DIE("Unexpected block header type");
90             }
91         } break;
92 
93         case type_t::if_statement:
94             src_end = node.as<if_statement_t>()->if_clause.condition.job.source_range().end();
95             break;
96 
97         case type_t::switch_statement:
98             src_end = node.as<switch_statement_t>()->semi_nl.source_range().start;
99             break;
100 
101         default:
102             DIE("Not a redirectable block type");
103             break;
104     }
105 
106     assert(src_end >= source_range->start && "Invalid source end");
107 
108     // Get the source for the block, and cut it at the next statement terminator.
109     wcstring result = pstree.src.substr(source_range->start, src_end - source_range->start);
110     result.append(L"...");
111     return result;
112 }
113 
114 /// Get a redirection from stderr to stdout (i.e. 2>&1).
get_stderr_merge()115 static redirection_spec_t get_stderr_merge() {
116     const wchar_t *stdout_fileno_str = L"1";
117     return redirection_spec_t{STDERR_FILENO, redirection_mode_t::fd, stdout_fileno_str};
118 }
119 
parse_execution_context_t(parsed_source_ref_t pstree,const operation_context_t & ctx,cancellation_group_ref_t cancel_group,io_chain_t block_io)120 parse_execution_context_t::parse_execution_context_t(parsed_source_ref_t pstree,
121                                                      const operation_context_t &ctx,
122                                                      cancellation_group_ref_t cancel_group,
123                                                      io_chain_t block_io)
124     : pstree(std::move(pstree)),
125       parser(ctx.parser.get()),
126       ctx(ctx),
127       cancel_group(std::move(cancel_group)),
128       block_io(std::move(block_io)) {}
129 
130 // Utilities
131 
get_source(const ast::node_t & node) const132 wcstring parse_execution_context_t::get_source(const ast::node_t &node) const {
133     return node.source(pstree->src);
134 }
135 
136 const ast::decorated_statement_t *
infinite_recursive_statement_in_job_list(const ast::job_list_t & jobs,wcstring * out_func_name) const137 parse_execution_context_t::infinite_recursive_statement_in_job_list(const ast::job_list_t &jobs,
138                                                                     wcstring *out_func_name) const {
139     // This is a bit fragile. It is a test to see if we are inside of function call, but not inside
140     // a block in that function call. If, in the future, the rules for what block scopes are pushed
141     // on function invocation changes, then this check will break.
142     const block_t *current = parser->block_at_index(0), *parent = parser->block_at_index(1);
143     bool is_within_function_call =
144         (current && parent && current->type() == block_type_t::top && parent->is_function_call());
145     if (!is_within_function_call) {
146         return nullptr;
147     }
148 
149     // Get the function name of the immediate block.
150     const wcstring &forbidden_function_name = parent->function_name;
151 
152     // Get the first job in the job list.
153     const ast::job_conjunction_t *jc = jobs.at(0);
154     if (!jc) return nullptr;
155     const ast::job_t *job = &jc->job;
156 
157     // Helper to return if a statement is infinitely recursive in this function.
158     auto statement_recurses =
159         [&](const ast::statement_t &stat) -> const ast::decorated_statement_t * {
160         // Ignore non-decorated statements like `if`, etc.
161         const ast::decorated_statement_t *dc =
162             stat.contents.contents->try_as<ast::decorated_statement_t>();
163         if (!dc) return nullptr;
164 
165         // Ignore statements with decorations like 'builtin' or 'command', since those
166         // are not infinite recursion. In particular that is what enables 'wrapper functions'.
167         if (dc->decoration() != statement_decoration_t::none) return nullptr;
168 
169         // Check the command.
170         wcstring cmd = dc->command.source(pstree->src);
171         bool forbidden =
172             !cmd.empty() &&
173             expand_one(cmd, {expand_flag::skip_cmdsubst, expand_flag::skip_variables}, ctx) &&
174             cmd == forbidden_function_name;
175         return forbidden ? dc : nullptr;
176     };
177 
178     const ast::decorated_statement_t *infinite_recursive_statement = nullptr;
179 
180     // Check main statement.
181     infinite_recursive_statement = statement_recurses(jc->job.statement);
182 
183     // Check piped remainder.
184     if (!infinite_recursive_statement) {
185         for (const ast::job_continuation_t &c : job->continuation) {
186             if (const auto *s = statement_recurses(c.statement)) {
187                 infinite_recursive_statement = s;
188                 break;
189             }
190         }
191     }
192 
193     if (infinite_recursive_statement && out_func_name) {
194         *out_func_name = forbidden_function_name;
195     }
196     // may be null
197     return infinite_recursive_statement;
198 }
199 
process_type_for_command(const ast::decorated_statement_t & statement,const wcstring & cmd) const200 process_type_t parse_execution_context_t::process_type_for_command(
201     const ast::decorated_statement_t &statement, const wcstring &cmd) const {
202     enum process_type_t process_type = process_type_t::external;
203 
204     // Determine the process type, which depends on the statement decoration (command, builtin,
205     // etc).
206     switch (statement.decoration()) {
207         case statement_decoration_t::exec:
208             process_type = process_type_t::exec;
209             break;
210         case statement_decoration_t::command:
211             process_type = process_type_t::external;
212             break;
213         case statement_decoration_t::builtin:
214             process_type = process_type_t::builtin;
215             break;
216         case statement_decoration_t::none:
217             if (function_exists(cmd, *parser)) {
218                 process_type = process_type_t::function;
219             } else if (builtin_exists(cmd)) {
220                 process_type = process_type_t::builtin;
221             } else {
222                 process_type = process_type_t::external;
223             }
224             break;
225     }
226 
227     return process_type;
228 }
229 
check_end_execution() const230 maybe_t<end_execution_reason_t> parse_execution_context_t::check_end_execution() const {
231     if (ctx.check_cancel() || check_cancel_from_fish_signal()) {
232         return end_execution_reason_t::cancelled;
233     }
234     const auto &ld = parser->libdata();
235     if (ld.exit_current_script) {
236         return end_execution_reason_t::cancelled;
237     }
238     if (ld.returning) {
239         return end_execution_reason_t::control_flow;
240     }
241     if (ld.loop_status != loop_status_t::normals) {
242         return end_execution_reason_t::control_flow;
243     }
244     return none();
245 }
246 
247 /// Return whether the job contains a single statement, of block type, with no redirections.
job_is_simple_block(const ast::job_t & job) const248 bool parse_execution_context_t::job_is_simple_block(const ast::job_t &job) const {
249     using namespace ast;
250     // Must be no pipes.
251     if (!job.continuation.empty()) {
252         return false;
253     }
254 
255     // Helper to check if an argument_or_redirection_list_t has no redirections.
256     auto no_redirs = [](const argument_or_redirection_list_t &list) -> bool {
257         for (const argument_or_redirection_t &val : list) {
258             if (val.is_redirection()) return false;
259         }
260         return true;
261     };
262 
263     // Check if we're a block statement with redirections. We do it this obnoxious way to preserve
264     // type safety (in case we add more specific statement types).
265     const node_t &ss = *job.statement.contents.contents;
266     switch (ss.type) {
267         case type_t::block_statement:
268             return no_redirs(ss.as<block_statement_t>()->args_or_redirs);
269         case type_t::switch_statement:
270             return no_redirs(ss.as<switch_statement_t>()->args_or_redirs);
271         case type_t::if_statement:
272             return no_redirs(ss.as<if_statement_t>()->args_or_redirs);
273         case type_t::not_statement:
274         case type_t::decorated_statement:
275             // not block statements
276             return false;
277         default:
278             assert(0 && "Unexpected child block type");
279             return false;
280     }
281 }
282 
run_if_statement(const ast::if_statement_t & statement,const block_t * associated_block)283 end_execution_reason_t parse_execution_context_t::run_if_statement(
284     const ast::if_statement_t &statement, const block_t *associated_block) {
285     using namespace ast;
286     using job_list_t = ast::job_list_t;
287     end_execution_reason_t result = end_execution_reason_t::ok;
288 
289     // We have a sequence of if clauses, with a final else, resulting in a single job list that we
290     // execute.
291     const job_list_t *job_list_to_execute = nullptr;
292     const if_clause_t *if_clause = &statement.if_clause;
293 
294     // Index of the *next* elseif_clause to test.
295     const elseif_clause_list_t &elseif_clauses = statement.elseif_clauses;
296     size_t next_elseif_idx = 0;
297 
298     // We start with the 'if'.
299     trace_if_enabled(*parser, L"if");
300 
301     for (;;) {
302         if (auto ret = check_end_execution()) {
303             result = *ret;
304             break;
305         }
306 
307         // An if condition has a job and a "tail" of andor jobs, e.g. "foo ; and bar; or baz".
308         // Check the condition and the tail. We treat end_execution_reason_t::error here as failure,
309         // in accordance with historic behavior.
310         end_execution_reason_t cond_ret =
311             run_job_conjunction(if_clause->condition, associated_block);
312         if (cond_ret == end_execution_reason_t::ok) {
313             cond_ret = run_job_list(if_clause->andor_tail, associated_block);
314         }
315         const bool take_branch =
316             (cond_ret == end_execution_reason_t::ok) && parser->get_last_status() == EXIT_SUCCESS;
317 
318         if (take_branch) {
319             // Condition succeeded.
320             job_list_to_execute = &if_clause->body;
321             break;
322         }
323 
324         // See if we have an elseif.
325         const auto *elseif_clause = elseif_clauses.at(next_elseif_idx++);
326         if (elseif_clause) {
327             trace_if_enabled(*parser, L"else if");
328             if_clause = &elseif_clause->if_clause;
329         } else {
330             break;
331         }
332     }
333 
334     if (!job_list_to_execute) {
335         // our ifs and elseifs failed.
336         // Check our else body.
337         if (statement.else_clause) {
338             trace_if_enabled(*parser, L"else");
339             job_list_to_execute = &statement.else_clause->body;
340         }
341     }
342 
343     if (!job_list_to_execute) {
344         // 'if' condition failed, no else clause, return 0, we're done.
345         // No job list means no successful conditions, so return 0 (issue #1443).
346         parser->set_last_statuses(statuses_t::just(STATUS_CMD_OK));
347     } else {
348         // Execute the job list we got.
349         block_t *ib = parser->push_block(block_t::if_block());
350         run_job_list(*job_list_to_execute, ib);
351         if (auto ret = check_end_execution()) {
352             result = *ret;
353         }
354         parser->pop_block(ib);
355     }
356     trace_if_enabled(*parser, L"end if");
357 
358     // It's possible there's a last-minute cancellation (issue #1297).
359     if (auto ret = check_end_execution()) {
360         result = *ret;
361     }
362 
363     // Otherwise, take the exit status of the job list. Reversal of issue #1061.
364     return result;
365 }
366 
run_begin_statement(const ast::job_list_t & contents)367 end_execution_reason_t parse_execution_context_t::run_begin_statement(
368     const ast::job_list_t &contents) {
369     // Basic begin/end block. Push a scope block, run jobs, pop it
370     trace_if_enabled(*parser, L"begin");
371     block_t *sb = parser->push_block(block_t::scope_block(block_type_t::begin));
372     end_execution_reason_t ret = run_job_list(contents, sb);
373     parser->pop_block(sb);
374     trace_if_enabled(*parser, L"end begin");
375     return ret;
376 }
377 
378 // Define a function.
run_function_statement(const ast::block_statement_t & statement,const ast::function_header_t & header)379 end_execution_reason_t parse_execution_context_t::run_function_statement(
380     const ast::block_statement_t &statement, const ast::function_header_t &header) {
381     using namespace ast;
382     // Get arguments.
383     wcstring_list_t arguments;
384     ast_args_list_t arg_nodes = get_argument_nodes(header.args);
385     arg_nodes.insert(arg_nodes.begin(), &header.first_arg);
386     end_execution_reason_t result =
387         this->expand_arguments_from_nodes(arg_nodes, &arguments, failglob);
388 
389     if (result != end_execution_reason_t::ok) {
390         return result;
391     }
392     trace_if_enabled(*parser, L"function", arguments);
393     null_output_stream_t outs;
394     string_output_stream_t errs;
395     io_streams_t streams(outs, errs);
396     int err_code = 0;
397     maybe_t<int> err = builtin_function(*parser, streams, arguments, pstree, statement);
398     if (err) {
399         err_code = err.value();
400         parser->libdata().status_count++;
401         parser->set_last_statuses(statuses_t::just(err_code));
402     }
403 
404     const wcstring &errtext = errs.contents();
405     if (!errtext.empty()) {
406         return this->report_error(err_code, header, L"%ls", errtext.c_str());
407     }
408     return result;
409 }
410 
run_block_statement(const ast::block_statement_t & statement,const block_t * associated_block)411 end_execution_reason_t parse_execution_context_t::run_block_statement(
412     const ast::block_statement_t &statement, const block_t *associated_block) {
413     const ast::node_t &bh = *statement.header.contents;
414     const ast::job_list_t &contents = statement.jobs;
415     end_execution_reason_t ret = end_execution_reason_t::ok;
416     if (const auto *fh = bh.try_as<ast::for_header_t>()) {
417         ret = run_for_statement(*fh, contents);
418     } else if (const auto *wh = bh.try_as<ast::while_header_t>()) {
419         ret = run_while_statement(*wh, contents, associated_block);
420     } else if (const auto *fh = bh.try_as<ast::function_header_t>()) {
421         ret = run_function_statement(statement, *fh);
422     } else if (bh.try_as<ast::begin_header_t>()) {
423         ret = run_begin_statement(contents);
424     } else {
425         FLOGF(error, L"Unexpected block header: %ls\n", bh.describe().c_str());
426         PARSER_DIE();
427     }
428     return ret;
429 }
430 
run_for_statement(const ast::for_header_t & header,const ast::job_list_t & block_contents)431 end_execution_reason_t parse_execution_context_t::run_for_statement(
432     const ast::for_header_t &header, const ast::job_list_t &block_contents) {
433     // Get the variable name: `for var_name in ...`. We expand the variable name. It better result
434     // in just one.
435     wcstring for_var_name = header.var_name.source(get_source());
436     if (!expand_one(for_var_name, expand_flags_t{}, ctx)) {
437         return report_error(STATUS_EXPAND_ERROR, header.var_name,
438                             FAILED_EXPANSION_VARIABLE_NAME_ERR_MSG, for_var_name.c_str());
439     }
440 
441     // Get the contents to iterate over.
442     wcstring_list_t arguments;
443     ast_args_list_t arg_nodes = get_argument_nodes(header.args);
444     end_execution_reason_t ret = this->expand_arguments_from_nodes(arg_nodes, &arguments, nullglob);
445     if (ret != end_execution_reason_t::ok) {
446         return ret;
447     }
448 
449     auto var = parser->vars().get(for_var_name, ENV_DEFAULT);
450     if (var && var->read_only()) {
451         return report_error(STATUS_INVALID_ARGS, header.var_name,
452                             L"You cannot use read-only variable '%ls' in a for loop",
453                             for_var_name.c_str());
454     }
455     int retval;
456     if (var) {
457         retval = parser->set_var_and_fire(for_var_name, ENV_LOCAL | ENV_USER, var->as_list());
458     } else {
459         retval = parser->set_empty_var_and_fire(for_var_name, ENV_LOCAL | ENV_USER);
460     }
461     assert(retval == ENV_OK);
462 
463     if (!valid_var_name(for_var_name)) {
464         return report_error(STATUS_INVALID_ARGS, header.var_name, BUILTIN_ERR_VARNAME, L"for",
465                             for_var_name.c_str());
466     }
467 
468     trace_if_enabled(*parser, L"for", arguments);
469     block_t *fb = parser->push_block(block_t::for_block());
470 
471     // Now drive the for loop.
472     for (const wcstring &val : arguments) {
473         if (auto reason = check_end_execution()) {
474             ret = *reason;
475             break;
476         }
477 
478         int retval = parser->set_var_and_fire(for_var_name, ENV_DEFAULT | ENV_USER, val);
479         assert(retval == ENV_OK && "for loop variable should have been successfully set");
480         (void)retval;
481 
482         auto &ld = parser->libdata();
483         ld.loop_status = loop_status_t::normals;
484         this->run_job_list(block_contents, fb);
485 
486         if (check_end_execution() == end_execution_reason_t::control_flow) {
487             // Handle break or continue.
488             bool do_break = (ld.loop_status == loop_status_t::breaks);
489             ld.loop_status = loop_status_t::normals;
490             if (do_break) {
491                 break;
492             }
493         }
494     }
495 
496     parser->pop_block(fb);
497     trace_if_enabled(*parser, L"end for");
498     return ret;
499 }
500 
run_switch_statement(const ast::switch_statement_t & statement)501 end_execution_reason_t parse_execution_context_t::run_switch_statement(
502     const ast::switch_statement_t &statement) {
503     // Get the switch variable.
504     const wcstring switch_value = get_source(statement.argument);
505 
506     // Expand it. We need to offset any errors by the position of the string.
507     completion_list_t switch_values_expanded;
508     parse_error_list_t errors;
509     auto expand_ret =
510         expand_string(switch_value, &switch_values_expanded, expand_flags_t{}, ctx, &errors);
511     parse_error_offset_source_start(&errors, statement.argument.range.start);
512 
513     switch (expand_ret.result) {
514         case expand_result_t::error:
515             return report_errors(expand_ret.status, errors);
516 
517         case expand_result_t::cancel:
518             return end_execution_reason_t::cancelled;
519 
520         case expand_result_t::wildcard_no_match:
521             return report_error(STATUS_UNMATCHED_WILDCARD, statement.argument, WILDCARD_ERR_MSG,
522                                 get_source(statement.argument).c_str());
523 
524         case expand_result_t::ok:
525             if (switch_values_expanded.size() > 1) {
526                 return report_error(STATUS_INVALID_ARGS, statement.argument,
527                                     _(L"switch: Expected at most one argument, got %lu\n"),
528                                     switch_values_expanded.size());
529             }
530             break;
531     }
532 
533     // If we expanded to nothing, match the empty string.
534     assert(switch_values_expanded.size() <= 1 && "Should have at most one expansion");
535     wcstring switch_value_expanded;
536     if (!switch_values_expanded.empty()) {
537         switch_value_expanded = std::move(switch_values_expanded.front().completion);
538     }
539 
540     end_execution_reason_t result = end_execution_reason_t::ok;
541     if (trace_enabled(*parser)) trace_argv(*parser, L"switch", {switch_value_expanded});
542     block_t *sb = parser->push_block(block_t::switch_block());
543 
544     // Expand case statements.
545     const ast::case_item_t *matching_case_item = nullptr;
546     for (const ast::case_item_t &case_item : statement.cases) {
547         if (auto ret = check_end_execution()) {
548             result = *ret;
549             break;
550         }
551 
552         // Expand arguments. A case item list may have a wildcard that fails to expand to
553         // anything. We also report case errors, but don't stop execution; i.e. a case item that
554         // contains an unexpandable process will report and then fail to match.
555         ast_args_list_t arg_nodes = get_argument_nodes(case_item.arguments);
556         wcstring_list_t case_args;
557         end_execution_reason_t case_result =
558             this->expand_arguments_from_nodes(arg_nodes, &case_args, failglob);
559         if (case_result == end_execution_reason_t::ok) {
560             for (const wcstring &arg : case_args) {
561                 // Unescape wildcards so they can be expanded again.
562                 wcstring unescaped_arg = parse_util_unescape_wildcards(arg);
563                 bool match = wildcard_match(switch_value_expanded, unescaped_arg);
564 
565                 // If this matched, we're done.
566                 if (match) {
567                     matching_case_item = &case_item;
568                     break;
569                 }
570             }
571         }
572         if (matching_case_item) break;
573     }
574 
575     if (matching_case_item) {
576         // Success, evaluate the job list.
577         assert(result == end_execution_reason_t::ok && "Expected success");
578         result = this->run_job_list(matching_case_item->body, sb);
579     }
580 
581     parser->pop_block(sb);
582     trace_if_enabled(*parser, L"end switch");
583     return result;
584 }
585 
run_while_statement(const ast::while_header_t & header,const ast::job_list_t & contents,const block_t * associated_block)586 end_execution_reason_t parse_execution_context_t::run_while_statement(
587     const ast::while_header_t &header, const ast::job_list_t &contents,
588     const block_t *associated_block) {
589     end_execution_reason_t ret = end_execution_reason_t::ok;
590 
591     // "The exit status of the while loop shall be the exit status of the last compound-list-2
592     // executed, or zero if none was executed."
593     // Here are more detailed requirements:
594     // - If we execute the loop body zero times, or the loop body is empty, the status is success.
595     // - An empty loop body is treated as true, both in the loop condition and after loop exit.
596     // - The exit status of the last command is visible in the loop condition. (i.e. do not set the
597     // exit status to true BEFORE executing the loop condition).
598     // We achieve this by restoring the status if the loop condition fails, plus a special
599     // affordance for the first condition.
600     bool first_cond_check = true;
601 
602     trace_if_enabled(*parser, L"while");
603 
604     // Run while the condition is true.
605     for (;;) {
606         // Save off the exit status if it came from the loop body. We'll restore it if the condition
607         // is false.
608         auto cond_saved_status =
609             first_cond_check ? statuses_t::just(EXIT_SUCCESS) : parser->get_last_statuses();
610         first_cond_check = false;
611 
612         // Check the condition.
613         end_execution_reason_t cond_ret =
614             this->run_job_conjunction(header.condition, associated_block);
615         if (cond_ret == end_execution_reason_t::ok) {
616             cond_ret = run_job_list(header.andor_tail, associated_block);
617         }
618 
619         // If the loop condition failed to execute, then exit the loop without modifying the exit
620         // status. If the loop condition executed with a failure status, restore the status and then
621         // exit the loop.
622         if (cond_ret != end_execution_reason_t::ok) {
623             break;
624         } else if (parser->get_last_status() != EXIT_SUCCESS) {
625             parser->set_last_statuses(cond_saved_status);
626             break;
627         }
628 
629         // Check cancellation.
630         if (auto reason = check_end_execution()) {
631             ret = *reason;
632             break;
633         }
634 
635         // Push a while block and then check its cancellation reason.
636         auto &ld = parser->libdata();
637         ld.loop_status = loop_status_t::normals;
638 
639         block_t *wb = parser->push_block(block_t::while_block());
640         this->run_job_list(contents, wb);
641         auto cancel_reason = this->check_end_execution();
642         parser->pop_block(wb);
643 
644         if (cancel_reason == end_execution_reason_t::control_flow) {
645             // Handle break or continue.
646             bool do_break = (ld.loop_status == loop_status_t::breaks);
647             ld.loop_status = loop_status_t::normals;
648             if (do_break) {
649                 break;
650             } else {
651                 continue;
652             }
653         }
654 
655         // no_exec means that fish was invoked with -n or --no-execute. If set, we allow the loop to
656         // not-execute once so its contents can be checked, and then break.
657         if (no_exec()) {
658             break;
659         }
660     }
661     trace_if_enabled(*parser, L"end while");
662     return ret;
663 }
664 
665 // Reports an error. Always returns end_execution_reason_t::error.
report_error(int status,const ast::node_t & node,const wchar_t * fmt,...) const666 end_execution_reason_t parse_execution_context_t::report_error(int status, const ast::node_t &node,
667                                                                const wchar_t *fmt, ...) const {
668     auto r = node.source_range();
669 
670     // Create an error.
671     parse_error_list_t error_list = parse_error_list_t(1);
672     parse_error_t *error = &error_list.at(0);
673     error->source_start = r.start;
674     error->source_length = r.length;
675     error->code = parse_error_syntax;  // hackish
676 
677     va_list va;
678     va_start(va, fmt);
679     error->text = vformat_string(fmt, va);
680     va_end(va);
681 
682     return this->report_errors(status, error_list);
683 }
684 
report_errors(int status,const parse_error_list_t & error_list) const685 end_execution_reason_t parse_execution_context_t::report_errors(
686     int status, const parse_error_list_t &error_list) const {
687     if (!ctx.check_cancel()) {
688         if (error_list.empty()) {
689             FLOG(error, L"Error reported but no error text found.");
690         }
691 
692         // Get a backtrace.
693         wcstring backtrace_and_desc;
694         parser->get_backtrace(pstree->src, error_list, backtrace_and_desc);
695 
696         // Print it.
697         if (!should_suppress_stderr_for_tests()) {
698             std::fwprintf(stderr, L"%ls", backtrace_and_desc.c_str());
699         }
700 
701         // Mark status.
702         parser->set_last_statuses(statuses_t::just(status));
703     }
704     return end_execution_reason_t::error;
705 }
706 
707 // static
get_argument_nodes(const ast::argument_list_t & args)708 parse_execution_context_t::ast_args_list_t parse_execution_context_t::get_argument_nodes(
709     const ast::argument_list_t &args) {
710     ast_args_list_t result;
711     for (const ast::argument_t &arg : args) result.push_back(&arg);
712     return result;
713 }
714 
715 // static
get_argument_nodes(const ast::argument_or_redirection_list_t & args)716 parse_execution_context_t::ast_args_list_t parse_execution_context_t::get_argument_nodes(
717     const ast::argument_or_redirection_list_t &args) {
718     ast_args_list_t result;
719     for (const ast::argument_or_redirection_t &v : args) {
720         if (v.is_argument()) result.push_back(&v.argument());
721     }
722     return result;
723 }
724 
725 /// Handle the case of command not found.
handle_command_not_found(const wcstring & cmd_str,const ast::decorated_statement_t & statement,int err_code)726 end_execution_reason_t parse_execution_context_t::handle_command_not_found(
727     const wcstring &cmd_str, const ast::decorated_statement_t &statement, int err_code) {
728     // We couldn't find the specified command. This is a non-fatal error. We want to set the exit
729     // status to 127, which is the standard number used by other shells like bash and zsh.
730 
731     const wchar_t *const cmd = cmd_str.c_str();
732     if (err_code != ENOENT) {
733         return this->report_error(STATUS_NOT_EXECUTABLE, statement,
734                                   _(L"The file '%ls' is not executable by this user"), cmd);
735     }
736 
737     // Handle unrecognized commands with standard command not found handler that can make better
738     // error messages.
739     wcstring_list_t event_args;
740     {
741         ast_args_list_t args = get_argument_nodes(statement.args_or_redirs);
742         end_execution_reason_t arg_result =
743             this->expand_arguments_from_nodes(args, &event_args, failglob);
744 
745         if (arg_result != end_execution_reason_t::ok) {
746             return arg_result;
747         }
748 
749         event_args.insert(event_args.begin(), cmd_str);
750     }
751 
752     wcstring buffer;
753     wcstring error;
754 
755     // Redirect to stderr
756     auto io = io_chain_t{};
757     io.append_from_specs({redirection_spec_t{STDOUT_FILENO, redirection_mode_t::fd, L"2"}}, L"");
758 
759     if (function_exists(L"fish_command_not_found", *parser)) {
760         buffer = L"fish_command_not_found";
761         for (const wcstring &arg : event_args) {
762             buffer.push_back(L' ');
763             buffer.append(escape_string(arg, ESCAPE_ALL));
764         }
765         auto prev_statuses = parser->get_last_statuses();
766 
767         event_t event(event_type_t::generic);
768         event.desc.str_param1 = L"fish_command_not_found";
769         block_t *b = parser->push_block(block_t::event_block(event));
770         parser->eval(buffer, io);
771         parser->pop_block(b);
772         parser->set_last_statuses(std::move(prev_statuses));
773     } else {
774         // If we have no handler, just print it as a normal error.
775         error = _(L"Unknown command:");
776         if (!event_args.empty()) {
777             error.push_back(L' ');
778             error.append(escape_string(event_args[0], ESCAPE_ALL));
779         }
780     }
781 
782     if (!cmd_str.empty() && cmd_str.at(0) == L'{') {
783         error.append(ERROR_NO_BRACE_GROUPING);
784     }
785 
786     // Here we want to report an error (so it shows a backtrace).
787     // If the handler printed text, that's already shown, so error will be empty.
788     return this->report_error(STATUS_CMD_UNKNOWN, statement, error.c_str());
789 }
790 
expand_command(const ast::decorated_statement_t & statement,wcstring * out_cmd,wcstring_list_t * out_args) const791 end_execution_reason_t parse_execution_context_t::expand_command(
792     const ast::decorated_statement_t &statement, wcstring *out_cmd,
793     wcstring_list_t *out_args) const {
794     // Here we're expanding a command, for example $HOME/bin/stuff or $randomthing. The first
795     // completion becomes the command itself, everything after becomes arguments. Command
796     // substitutions are not supported.
797     parse_error_list_t errors;
798 
799     // Get the unexpanded command string. We expect to always get it here.
800     wcstring unexp_cmd = get_source(statement.command);
801     size_t pos_of_command_token = statement.command.range.start;
802 
803     // Expand the string to produce completions, and report errors.
804     expand_result_t expand_err =
805         expand_to_command_and_args(unexp_cmd, ctx, out_cmd, out_args, &errors);
806     if (expand_err == expand_result_t::error) {
807         // Issue #5812 - the expansions were done on the command token,
808         // excluding prefixes such as " " or "if ".
809         // This means that the error positions are relative to the beginning
810         // of the token; we need to make them relative to the original source.
811         parse_error_offset_source_start(&errors, pos_of_command_token);
812         return report_errors(STATUS_ILLEGAL_CMD, errors);
813     } else if (expand_err == expand_result_t::wildcard_no_match) {
814         return report_error(STATUS_UNMATCHED_WILDCARD, statement, WILDCARD_ERR_MSG,
815                             get_source(statement).c_str());
816     }
817     assert(expand_err == expand_result_t::ok);
818 
819     // Complain if the resulting expansion was empty, or expanded to an empty string.
820     // For no-exec it's okay, as we can't really perform the expansion.
821     if (out_cmd->empty() && !no_exec()) {
822         return this->report_error(STATUS_ILLEGAL_CMD, statement,
823                                   _(L"The expanded command was empty."));
824     }
825     return end_execution_reason_t::ok;
826 }
827 
828 /// Creates a 'normal' (non-block) process.
populate_plain_process(job_t * job,process_t * proc,const ast::decorated_statement_t & statement)829 end_execution_reason_t parse_execution_context_t::populate_plain_process(
830     job_t *job, process_t *proc, const ast::decorated_statement_t &statement) {
831     assert(job != nullptr);
832     assert(proc != nullptr);
833 
834     // We may decide that a command should be an implicit cd.
835     bool use_implicit_cd = false;
836 
837     // Get the command and any arguments due to expanding the command.
838     wcstring cmd;
839     wcstring_list_t args_from_cmd_expansion;
840     auto ret = expand_command(statement, &cmd, &args_from_cmd_expansion);
841     if (ret != end_execution_reason_t::ok) {
842         return ret;
843     }
844     // For no-exec, having an empty command is okay. We can't do anything more with it tho.
845     if (no_exec()) return end_execution_reason_t::ok;
846     assert(!cmd.empty() && "expand_command should not produce an empty command");
847 
848     // Determine the process type.
849     enum process_type_t process_type = process_type_for_command(statement, cmd);
850 
851     wcstring path_to_external_command;
852     if (process_type == process_type_t::external || process_type == process_type_t::exec) {
853         // Determine the actual command. This may be an implicit cd.
854         bool has_command = path_get_path(cmd, &path_to_external_command, parser->vars());
855 
856         // If there was no command, then we care about the value of errno after checking for it, to
857         // distinguish between e.g. no file vs permissions problem.
858         const int no_cmd_err_code = errno;
859 
860         // If the specified command does not exist, and is undecorated, try using an implicit cd.
861         if (!has_command && statement.decoration() == statement_decoration_t::none) {
862             // Implicit cd requires an empty argument and redirection list.
863             if (statement.args_or_redirs.empty()) {
864                 // Ok, no arguments or redirections; check to see if the command is a directory.
865                 use_implicit_cd =
866                     path_as_implicit_cd(cmd, parser->vars().get_pwd_slash(), parser->vars())
867                         .has_value();
868             }
869         }
870 
871         if (!has_command && !use_implicit_cd) {
872             // No command. If we're --no-execute return okay - it might be a function.
873             if (no_exec()) return end_execution_reason_t::ok;
874             return this->handle_command_not_found(cmd, statement, no_cmd_err_code);
875         }
876     }
877 
878     // Produce the full argument list and the set of IO redirections.
879     wcstring_list_t cmd_args;
880     redirection_spec_list_t redirections;
881     if (use_implicit_cd) {
882         // Implicit cd is simple.
883         cmd_args = {L"cd", cmd};
884         path_to_external_command.clear();
885 
886         // If we have defined a wrapper around cd, use it, otherwise use the cd builtin.
887         process_type =
888             function_exists(L"cd", *parser) ? process_type_t::function : process_type_t::builtin;
889     } else {
890         // Not implicit cd.
891         const globspec_t glob_behavior = (cmd == L"set" || cmd == L"count") ? nullglob : failglob;
892         // Form the list of arguments. The command is the first argument, followed by any arguments
893         // from expanding the command, followed by the argument nodes themselves. E.g. if the
894         // command is '$gco foo' and $gco is git checkout.
895         cmd_args.push_back(cmd);
896         cmd_args.insert(cmd_args.end(), args_from_cmd_expansion.begin(),
897                         args_from_cmd_expansion.end());
898 
899         ast_args_list_t arg_nodes = get_argument_nodes(statement.args_or_redirs);
900         end_execution_reason_t arg_result =
901             this->expand_arguments_from_nodes(arg_nodes, &cmd_args, glob_behavior);
902         if (arg_result != end_execution_reason_t::ok) {
903             return arg_result;
904         }
905 
906         // The set of IO redirections that we construct for the process.
907         auto reason = this->determine_redirections(statement.args_or_redirs, &redirections);
908         if (reason != end_execution_reason_t::ok) {
909             return reason;
910         }
911 
912         // Determine the process type.
913         process_type = process_type_for_command(statement, cmd);
914     }
915 
916     // Populate the process.
917     proc->type = process_type;
918     proc->set_argv(cmd_args);
919     proc->set_redirection_specs(std::move(redirections));
920     proc->actual_cmd = std::move(path_to_external_command);
921     return end_execution_reason_t::ok;
922 }
923 
924 // Determine the list of arguments, expanding stuff. Reports any errors caused by expansion. If we
925 // have a wildcard that could not be expanded, report the error and continue.
expand_arguments_from_nodes(const ast_args_list_t & argument_nodes,wcstring_list_t * out_arguments,globspec_t glob_behavior)926 end_execution_reason_t parse_execution_context_t::expand_arguments_from_nodes(
927     const ast_args_list_t &argument_nodes, wcstring_list_t *out_arguments,
928     globspec_t glob_behavior) {
929     // Get all argument nodes underneath the statement. We guess we'll have that many arguments (but
930     // may have more or fewer, if there are wildcards involved).
931     out_arguments->reserve(out_arguments->size() + argument_nodes.size());
932     completion_list_t arg_expanded;
933     for (const ast::argument_t *arg_node : argument_nodes) {
934         // Expect all arguments to have source.
935         assert(arg_node->has_source() && "Argument should have source");
936 
937         // Expand this string.
938         parse_error_list_t errors;
939         arg_expanded.clear();
940         auto expand_ret =
941             expand_string(get_source(*arg_node), &arg_expanded, expand_flags_t{}, ctx, &errors);
942         parse_error_offset_source_start(&errors, arg_node->range.start);
943         switch (expand_ret.result) {
944             case expand_result_t::error: {
945                 return this->report_errors(expand_ret.status, errors);
946             }
947 
948             case expand_result_t::cancel: {
949                 return end_execution_reason_t::cancelled;
950             }
951             case expand_result_t::wildcard_no_match: {
952                 if (glob_behavior == failglob) {
953                     // For no_exec, ignore the error - this might work at runtime.
954                     if (no_exec()) return end_execution_reason_t::ok;
955                     // Report the unmatched wildcard error and stop processing.
956                     return report_error(STATUS_UNMATCHED_WILDCARD, *arg_node, WILDCARD_ERR_MSG,
957                                         get_source(*arg_node).c_str());
958                 }
959                 break;
960             }
961             case expand_result_t::ok: {
962                 break;
963             }
964             default: {
965                 DIE("unexpected expand_string() return value");
966             }
967         }
968 
969         // Now copy over any expanded arguments. Use std::move() to avoid extra allocations; this
970         // is called very frequently.
971         out_arguments->reserve(out_arguments->size() + arg_expanded.size());
972         for (completion_t &new_arg : arg_expanded) {
973             out_arguments->push_back(std::move(new_arg.completion));
974         }
975     }
976 
977     // We may have received a cancellation during this expansion.
978     if (auto ret = check_end_execution()) {
979         return *ret;
980     }
981 
982     return end_execution_reason_t::ok;
983 }
984 
determine_redirections(const ast::argument_or_redirection_list_t & list,redirection_spec_list_t * out_redirections)985 end_execution_reason_t parse_execution_context_t::determine_redirections(
986     const ast::argument_or_redirection_list_t &list, redirection_spec_list_t *out_redirections) {
987     // Get all redirection nodes underneath the statement.
988     for (const ast::argument_or_redirection_t &arg_or_redir : list) {
989         if (!arg_or_redir.is_redirection()) continue;
990         const ast::redirection_t &redir_node = arg_or_redir.redirection();
991 
992         maybe_t<pipe_or_redir_t> oper = pipe_or_redir_t::from_string(get_source(redir_node.oper));
993         if (!oper || !oper->is_valid()) {
994             // TODO: figure out if this can ever happen. If so, improve this error message.
995             return report_error(STATUS_INVALID_ARGS, redir_node, _(L"Invalid redirection: %ls"),
996                                 get_source(redir_node).c_str());
997         }
998 
999         // PCA: I can't justify this skip_variables flag. It was like this when I got here.
1000         wcstring target = get_source(redir_node.target);
1001         bool target_expanded =
1002             expand_one(target, no_exec() ? expand_flag::skip_variables : expand_flags_t{}, ctx);
1003         if (!target_expanded || target.empty()) {
1004             // TODO: Improve this error message.
1005             return report_error(STATUS_INVALID_ARGS, redir_node,
1006                                 _(L"Invalid redirection target: %ls"), target.c_str());
1007         }
1008 
1009         // Make a redirection spec from the redirect token.
1010         assert(oper && oper->is_valid() && "expected to have a valid redirection");
1011         redirection_spec_t spec{oper->fd, oper->mode, std::move(target)};
1012 
1013         // Validate this spec.
1014         if (spec.mode == redirection_mode_t::fd && !spec.is_close() && !spec.get_target_as_fd()) {
1015             const wchar_t *fmt =
1016                 _(L"Requested redirection to '%ls', which is not a valid file descriptor");
1017             return report_error(STATUS_INVALID_ARGS, redir_node, fmt, spec.target.c_str());
1018         }
1019         out_redirections->push_back(std::move(spec));
1020 
1021         if (oper->stderr_merge) {
1022             // This was a redirect like &> which also modifies stderr.
1023             // Also redirect stderr to stdout.
1024             out_redirections->push_back(get_stderr_merge());
1025         }
1026     }
1027     return end_execution_reason_t::ok;
1028 }
1029 
populate_not_process(job_t * job,process_t * proc,const ast::not_statement_t & not_statement)1030 end_execution_reason_t parse_execution_context_t::populate_not_process(
1031     job_t *job, process_t *proc, const ast::not_statement_t &not_statement) {
1032     auto &flags = job->mut_flags();
1033     flags.negate = !flags.negate;
1034     return this->populate_job_process(job, proc, not_statement.contents, not_statement.variables);
1035 }
1036 
1037 template <typename Type>
populate_block_process(job_t * job,process_t * proc,const ast::statement_t & statement,const Type & specific_statement)1038 end_execution_reason_t parse_execution_context_t::populate_block_process(
1039     job_t *job, process_t *proc, const ast::statement_t &statement,
1040     const Type &specific_statement) {
1041     using namespace ast;
1042     // We handle block statements by creating process_type_t::block_node, that will bounce back to
1043     // us when it's time to execute them.
1044     UNUSED(job);
1045     static_assert(Type::AstType == type_t::block_statement ||
1046                       Type::AstType == type_t::if_statement ||
1047                       Type::AstType == type_t::switch_statement,
1048                   "Invalid block process");
1049 
1050     // Get the argument or redirections list.
1051     // TODO: args_or_redirs should be available without resolving the statement type.
1052     const argument_or_redirection_list_t *args_or_redirs = nullptr;
1053 
1054     // Upcast to permit dropping the 'template' keyword.
1055     const node_t &ss = specific_statement;
1056     switch (Type::AstType) {
1057         case type_t::block_statement:
1058             args_or_redirs = &ss.as<block_statement_t>()->args_or_redirs;
1059             break;
1060         case type_t::if_statement:
1061             args_or_redirs = &ss.as<if_statement_t>()->args_or_redirs;
1062             break;
1063         case type_t::switch_statement:
1064             args_or_redirs = &ss.as<switch_statement_t>()->args_or_redirs;
1065             break;
1066         default:
1067             DIE("Unexpected block node type");
1068     }
1069     assert(args_or_redirs && "Should have args_or_redirs");
1070 
1071     redirection_spec_list_t redirections;
1072     auto reason = this->determine_redirections(*args_or_redirs, &redirections);
1073     if (reason == end_execution_reason_t::ok) {
1074         proc->type = process_type_t::block_node;
1075         proc->block_node_source = pstree;
1076         proc->internal_block_node = &statement;
1077         proc->set_redirection_specs(std::move(redirections));
1078     }
1079     return reason;
1080 }
1081 
apply_variable_assignments(process_t * proc,const ast::variable_assignment_list_t & variable_assignment_list,const block_t ** block)1082 end_execution_reason_t parse_execution_context_t::apply_variable_assignments(
1083     process_t *proc, const ast::variable_assignment_list_t &variable_assignment_list,
1084     const block_t **block) {
1085     if (variable_assignment_list.empty()) return end_execution_reason_t::ok;
1086     *block = parser->push_block(block_t::variable_assignment_block());
1087     for (const ast::variable_assignment_t &variable_assignment : variable_assignment_list) {
1088         const wcstring &source = get_source(variable_assignment);
1089         auto equals_pos = variable_assignment_equals_pos(source);
1090         assert(equals_pos);
1091         const wcstring variable_name = source.substr(0, *equals_pos);
1092         const wcstring expression = source.substr(*equals_pos + 1);
1093         completion_list_t expression_expanded;
1094         parse_error_list_t errors;
1095         // TODO this is mostly copied from expand_arguments_from_nodes, maybe extract to function
1096         auto expand_ret =
1097             expand_string(expression, &expression_expanded, expand_flags_t{}, ctx, &errors);
1098         parse_error_offset_source_start(&errors, variable_assignment.range.start + *equals_pos + 1);
1099         switch (expand_ret.result) {
1100             case expand_result_t::error:
1101                 return this->report_errors(expand_ret.status, errors);
1102 
1103             case expand_result_t::cancel:
1104                 return end_execution_reason_t::cancelled;
1105 
1106             case expand_result_t::wildcard_no_match:  // nullglob (equivalent to set)
1107             case expand_result_t::ok:
1108                 break;
1109 
1110             default: {
1111                 DIE("unexpected expand_string() return value");
1112             }
1113         }
1114         wcstring_list_t vals;
1115         for (auto &completion : expression_expanded) {
1116             vals.emplace_back(std::move(completion.completion));
1117         }
1118         if (proc) proc->variable_assignments.push_back({variable_name, vals});
1119         parser->set_var_and_fire(variable_name, ENV_LOCAL | ENV_EXPORT, std::move(vals));
1120     }
1121     return end_execution_reason_t::ok;
1122 }
1123 
populate_job_process(job_t * job,process_t * proc,const ast::statement_t & statement,const ast::variable_assignment_list_t & variable_assignments)1124 end_execution_reason_t parse_execution_context_t::populate_job_process(
1125     job_t *job, process_t *proc, const ast::statement_t &statement,
1126     const ast::variable_assignment_list_t &variable_assignments) {
1127     using namespace ast;
1128     // Get the "specific statement" which is boolean / block / if / switch / decorated.
1129     const node_t &specific_statement = *statement.contents.contents;
1130 
1131     const block_t *block = nullptr;
1132     end_execution_reason_t result =
1133         this->apply_variable_assignments(proc, variable_assignments, &block);
1134     cleanup_t scope([&]() {
1135         if (block) parser->pop_block(block);
1136     });
1137     if (result != end_execution_reason_t::ok) return result;
1138 
1139     switch (specific_statement.type) {
1140         case type_t::not_statement: {
1141             result =
1142                 this->populate_not_process(job, proc, *specific_statement.as<not_statement_t>());
1143             break;
1144         }
1145         case type_t::block_statement:
1146             result = this->populate_block_process(job, proc, statement,
1147                                                   *specific_statement.as<block_statement_t>());
1148             break;
1149         case type_t::if_statement:
1150             result = this->populate_block_process(job, proc, statement,
1151                                                   *specific_statement.as<if_statement_t>());
1152             break;
1153         case type_t::switch_statement:
1154             result = this->populate_block_process(job, proc, statement,
1155                                                   *specific_statement.as<switch_statement_t>());
1156             break;
1157         case type_t::decorated_statement: {
1158             result = this->populate_plain_process(job, proc,
1159                                                   *specific_statement.as<decorated_statement_t>());
1160             break;
1161         }
1162         default: {
1163             FLOGF(error, L"'%ls' not handled by new parser yet.",
1164                   specific_statement.describe().c_str());
1165             PARSER_DIE();
1166             break;
1167         }
1168     }
1169 
1170     return result;
1171 }
1172 
populate_job_from_job_node(job_t * j,const ast::job_t & job_node,const block_t * associated_block)1173 end_execution_reason_t parse_execution_context_t::populate_job_from_job_node(
1174     job_t *j, const ast::job_t &job_node, const block_t *associated_block) {
1175     UNUSED(associated_block);
1176 
1177     // We are going to construct process_t structures for every statement in the job.
1178     // Create processes. Each one may fail.
1179     process_list_t processes;
1180     processes.emplace_back(new process_t());
1181     end_execution_reason_t result = this->populate_job_process(
1182         j, processes.back().get(), job_node.statement, job_node.variables);
1183 
1184     // Construct process_ts for job continuations (pipelines).
1185     for (const ast::job_continuation_t &jc : job_node.continuation) {
1186         if (result != end_execution_reason_t::ok) {
1187             break;
1188         }
1189         // Handle the pipe, whose fd may not be the obvious stdout.
1190         auto parsed_pipe = pipe_or_redir_t::from_string(get_source(jc.pipe));
1191         assert(parsed_pipe.has_value() && parsed_pipe->is_pipe && "Failed to parse valid pipe");
1192         if (!parsed_pipe->is_valid()) {
1193             result = report_error(STATUS_INVALID_ARGS, jc.pipe, ILLEGAL_FD_ERR_MSG,
1194                                   get_source(jc.pipe).c_str());
1195             break;
1196         }
1197         processes.back()->pipe_write_fd = parsed_pipe->fd;
1198         if (parsed_pipe->stderr_merge) {
1199             // This was a pipe like &| which redirects both stdout and stderr.
1200             // Also redirect stderr to stdout.
1201             auto specs = processes.back()->redirection_specs();
1202             specs.push_back(get_stderr_merge());
1203             processes.back()->set_redirection_specs(std::move(specs));
1204         }
1205 
1206         // Store the new process (and maybe with an error).
1207         processes.emplace_back(new process_t());
1208         result = this->populate_job_process(j, processes.back().get(), jc.statement, jc.variables);
1209     }
1210 
1211     // Inform our processes of who is first and last
1212     processes.front()->is_first_in_job = true;
1213     processes.back()->is_last_in_job = true;
1214 
1215     // Return what happened.
1216     if (result == end_execution_reason_t::ok) {
1217         // Link up the processes.
1218         assert(!processes.empty());  //!OCLINT(multiple unary operator)
1219         j->processes = std::move(processes);
1220     }
1221     return result;
1222 }
1223 
remove_job(parser_t & parser,job_t * job)1224 static bool remove_job(parser_t &parser, job_t *job) {
1225     for (auto j = parser.jobs().begin(); j != parser.jobs().end(); ++j) {
1226         if (j->get() == job) {
1227             parser.jobs().erase(j);
1228             return true;
1229         }
1230     }
1231     return false;
1232 }
1233 
1234 /// Decide if a job node should be 'time'd.
1235 /// For historical reasons the 'not' and 'time' prefix are "inside out". That is, it's
1236 /// 'not time cmd'. Note that a time appearing anywhere in the pipeline affects the whole job.
1237 /// `sleep 1 | not time true` will time the whole job!
job_node_wants_timing(const ast::job_t & job_node)1238 static bool job_node_wants_timing(const ast::job_t &job_node) {
1239     // Does our job have the job-level time prefix?
1240     if (job_node.time) return true;
1241 
1242     // Helper to return true if a node is 'not time ...' or 'not not time...' or...
1243     auto is_timed_not_statement = [](const ast::statement_t &stat) {
1244         const auto *ns = stat.contents->try_as<ast::not_statement_t>();
1245         while (ns) {
1246             if (ns->time) return true;
1247             ns = ns->contents.try_as<ast::not_statement_t>();
1248         }
1249         return false;
1250     };
1251 
1252     // Do we have a 'not time ...' anywhere in our pipeline?
1253     if (is_timed_not_statement(job_node.statement)) return true;
1254     for (const ast::job_continuation_t &jc : job_node.continuation) {
1255         if (is_timed_not_statement(jc.statement)) return true;
1256     }
1257     return false;
1258 }
1259 
run_1_job(const ast::job_t & job_node,const block_t * associated_block)1260 end_execution_reason_t parse_execution_context_t::run_1_job(const ast::job_t &job_node,
1261                                                             const block_t *associated_block) {
1262     if (auto ret = check_end_execution()) {
1263         return *ret;
1264     }
1265 
1266     // We definitely do not want to execute anything if we're told we're --no-execute!
1267     if (no_exec()) return end_execution_reason_t::ok;
1268 
1269     // Get terminal modes.
1270     struct termios tmodes = {};
1271     if (parser->is_interactive() && tcgetattr(STDIN_FILENO, &tmodes)) {
1272         // Need real error handling here.
1273         wperror(L"tcgetattr");
1274         parser->set_last_statuses(statuses_t::just(STATUS_CMD_ERROR));
1275         return end_execution_reason_t::error;
1276     }
1277 
1278     // Increment the eval_level for the duration of this command.
1279     scoped_push<int> saved_eval_level(&parser->eval_level, parser->eval_level + 1);
1280 
1281     // Save the node index.
1282     scoped_push<const ast::job_t *> saved_node(&executing_job_node, &job_node);
1283 
1284     // Profiling support.
1285     profile_item_t *profile_item = this->parser->create_profile_item();
1286     const auto start_time = profile_item ? profile_item_t::now() : 0;
1287 
1288     // When we encounter a block construct (e.g. while loop) in the general case, we create a "block
1289     // process" containing its node. This allows us to handle block-level redirections.
1290     // However, if there are no redirections, then we can just jump into the block directly, which
1291     // is significantly faster.
1292     if (job_is_simple_block(job_node)) {
1293         bool do_time = job_node.time.has_value();
1294         // If no-exec has been given, there is nothing to time.
1295         cleanup_t timer = push_timer(do_time && !no_exec());
1296         const block_t *block = nullptr;
1297         end_execution_reason_t result =
1298             this->apply_variable_assignments(nullptr, job_node.variables, &block);
1299         cleanup_t scope([&]() {
1300             if (block) parser->pop_block(block);
1301         });
1302 
1303         const ast::node_t *specific_statement = job_node.statement.contents.get();
1304         assert(specific_statement_type_is_redirectable_block(*specific_statement));
1305         if (result == end_execution_reason_t::ok) {
1306             switch (specific_statement->type) {
1307                 case ast::type_t::block_statement: {
1308                     result = this->run_block_statement(
1309                         *specific_statement->as<ast::block_statement_t>(), associated_block);
1310                     break;
1311                 }
1312                 case ast::type_t::if_statement: {
1313                     result = this->run_if_statement(*specific_statement->as<ast::if_statement_t>(),
1314                                                     associated_block);
1315                     break;
1316                 }
1317                 case ast::type_t::switch_statement: {
1318                     result = this->run_switch_statement(
1319                         *specific_statement->as<ast::switch_statement_t>());
1320                     break;
1321                 }
1322                 default: {
1323                     // Other types should be impossible due to the
1324                     // specific_statement_type_is_redirectable_block check.
1325                     PARSER_DIE();
1326                     break;
1327                 }
1328             }
1329         }
1330 
1331         if (profile_item != nullptr) {
1332             profile_item->duration = profile_item_t::now() - start_time;
1333             profile_item->level = parser->eval_level;
1334             profile_item->cmd =
1335                 profiling_cmd_name_for_redirectable_block(*specific_statement, *this->pstree);
1336             profile_item->skipped = false;
1337         }
1338 
1339         return result;
1340     }
1341 
1342     const auto &ld = parser->libdata();
1343 
1344     auto job_control_mode = get_job_control_mode();
1345     bool wants_job_control =
1346         (job_control_mode == job_control_t::all) ||
1347         ((job_control_mode == job_control_t::interactive) && parser->is_interactive()) ||
1348         (ctx.job_group && ctx.job_group->wants_job_control());
1349 
1350     job_t::properties_t props{};
1351     props.initial_background = job_node.bg.has_value();
1352     props.skip_notification =
1353         ld.is_subshell || ld.is_block || ld.is_event || !parser->is_interactive();
1354     props.from_event_handler = ld.is_event;
1355     props.job_control = wants_job_control;
1356     props.wants_timing = job_node_wants_timing(job_node);
1357 
1358     // It's an error to have 'time' in a background job.
1359     if (props.wants_timing && props.initial_background) {
1360         return this->report_error(STATUS_INVALID_ARGS, job_node, ERROR_TIME_BACKGROUND);
1361     }
1362 
1363     shared_ptr<job_t> job = std::make_shared<job_t>(props, get_source(job_node));
1364 
1365     // We are about to populate a job. One possible argument to the job is a command substitution
1366     // which may be interested in the job that's populating it, via '--on-job-exit caller'. Record
1367     // the job ID here.
1368     scoped_push<internal_job_id_t> caller_id(&parser->libdata().caller_id, job->internal_job_id);
1369 
1370     // Populate the job. This may fail for reasons like command_not_found. If this fails, an error
1371     // will have been printed.
1372     end_execution_reason_t pop_result =
1373         this->populate_job_from_job_node(job.get(), job_node, associated_block);
1374     caller_id.restore();
1375 
1376     // Clean up the job on failure or cancellation.
1377     if (pop_result == end_execution_reason_t::ok) {
1378         // Resolve the job's group and mark if this job is the first to get it.
1379         job->group = job_group_t::resolve_group_for_job(*job, cancel_group, ctx.job_group);
1380         assert(job->group && "Should not have a null group");
1381         job->mut_flags().is_group_root = (job->group != ctx.job_group);
1382 
1383         // Success. Give the job to the parser - it will clean it up.
1384         parser->job_add(job);
1385 
1386         // Check to see if this contained any external commands.
1387         bool job_contained_external_command = false;
1388         for (const auto &proc : job->processes) {
1389             if (proc->type == process_type_t::external) {
1390                 job_contained_external_command = true;
1391                 break;
1392             }
1393         }
1394 
1395         // Actually execute the job.
1396         if (!exec_job(*parser, job, block_io)) {
1397             // No process in the job successfully launched.
1398             // Ensure statuses are set (#7540).
1399             if (auto statuses = job->get_statuses()) {
1400                 parser->set_last_statuses(statuses.value());
1401                 parser->libdata().status_count++;
1402             }
1403             remove_job(*this->parser, job.get());
1404         }
1405 
1406         // Update universal variables on external conmmands.
1407         // TODO: justify this, why not on every command?
1408         if (job_contained_external_command) {
1409             parser->vars().universal_barrier();
1410         }
1411     }
1412 
1413     if (profile_item != nullptr) {
1414         profile_item->duration = profile_item_t::now() - start_time;
1415         profile_item->level = parser->eval_level;
1416         profile_item->cmd = job ? job->command() : wcstring();
1417         profile_item->skipped = (pop_result != end_execution_reason_t::ok);
1418     }
1419 
1420     job_reap(*parser, false);  // clean up jobs
1421     return pop_result;
1422 }
1423 
run_job_conjunction(const ast::job_conjunction_t & job_expr,const block_t * associated_block)1424 end_execution_reason_t parse_execution_context_t::run_job_conjunction(
1425     const ast::job_conjunction_t &job_expr, const block_t *associated_block) {
1426     if (auto reason = check_end_execution()) {
1427         return *reason;
1428     }
1429     end_execution_reason_t result = run_1_job(job_expr.job, associated_block);
1430 
1431     for (const ast::job_conjunction_continuation_t &jc : job_expr.continuations) {
1432         if (result != end_execution_reason_t::ok) {
1433             return result;
1434         }
1435         if (auto reason = check_end_execution()) {
1436             return *reason;
1437         }
1438         // Check the conjunction type.
1439         bool skip = false;
1440         switch (jc.conjunction.type) {
1441             case parse_token_type_t::andand:
1442                 // AND. Skip if the last job failed.
1443                 skip = parser->get_last_status() != 0;
1444                 break;
1445             case parse_token_type_t::oror:
1446                 // OR. Skip if the last job succeeded.
1447                 skip = parser->get_last_status() == 0;
1448                 break;
1449             default:
1450                 DIE("Unexpected job conjunction type");
1451         }
1452         if (!skip) {
1453             result = run_1_job(jc.job, associated_block);
1454         }
1455     }
1456     return result;
1457 }
1458 
test_and_run_1_job_conjunction(const ast::job_conjunction_t & jc,const block_t * associated_block)1459 end_execution_reason_t parse_execution_context_t::test_and_run_1_job_conjunction(
1460     const ast::job_conjunction_t &jc, const block_t *associated_block) {
1461     // Test this job conjunction if it has an 'and' or 'or' decorator.
1462     // If it passes, then run it.
1463     if (auto reason = check_end_execution()) {
1464         return *reason;
1465     }
1466     // Maybe skip the job if it has a leading and/or.
1467     bool skip = false;
1468     if (jc.decorator.has_value()) {
1469         switch (jc.decorator->kw) {
1470             case parse_keyword_t::kw_and:
1471                 // AND. Skip if the last job failed.
1472                 skip = parser->get_last_status() != 0;
1473                 break;
1474             case parse_keyword_t::kw_or:
1475                 // OR. Skip if the last job succeeded.
1476                 skip = parser->get_last_status() == 0;
1477                 break;
1478             default:
1479                 DIE("Unexpected keyword");
1480         }
1481     }
1482     // Skipping is treated as success.
1483     if (skip) {
1484         return end_execution_reason_t::ok;
1485     } else {
1486         return this->run_job_conjunction(jc, associated_block);
1487     }
1488 }
1489 
run_job_list(const ast::job_list_t & job_list_node,const block_t * associated_block)1490 end_execution_reason_t parse_execution_context_t::run_job_list(const ast::job_list_t &job_list_node,
1491                                                                const block_t *associated_block) {
1492     auto result = end_execution_reason_t::ok;
1493     for (const ast::job_conjunction_t &jc : job_list_node) {
1494         result = test_and_run_1_job_conjunction(jc, associated_block);
1495     }
1496     // Returns the result of the last job executed or skipped.
1497     return result;
1498 }
1499 
run_job_list(const ast::andor_job_list_t & job_list_node,const block_t * associated_block)1500 end_execution_reason_t parse_execution_context_t::run_job_list(
1501     const ast::andor_job_list_t &job_list_node, const block_t *associated_block) {
1502     auto result = end_execution_reason_t::ok;
1503     for (const ast::andor_job_t &aoj : job_list_node) {
1504         result = test_and_run_1_job_conjunction(aoj.job, associated_block);
1505     }
1506     // Returns the result of the last job executed or skipped.
1507     return result;
1508 }
1509 
eval_node(const ast::statement_t & statement,const block_t * associated_block)1510 end_execution_reason_t parse_execution_context_t::eval_node(const ast::statement_t &statement,
1511                                                             const block_t *associated_block) {
1512     // Note we only expect block-style statements here. No not statements.
1513     enum end_execution_reason_t status = end_execution_reason_t::ok;
1514     const ast::node_t *contents = statement.contents.get();
1515     if (const auto *block = contents->try_as<ast::block_statement_t>()) {
1516         status = this->run_block_statement(*block, associated_block);
1517     } else if (const auto *ifstat = contents->try_as<ast::if_statement_t>()) {
1518         status = this->run_if_statement(*ifstat, associated_block);
1519     } else if (const auto *switchstat = contents->try_as<ast::switch_statement_t>()) {
1520         status = this->run_switch_statement(*switchstat);
1521     } else {
1522         FLOGF(error, L"Unexpected node %ls found in %s", statement.describe().c_str(),
1523               __FUNCTION__);
1524         abort();
1525     }
1526     return status;
1527 }
1528 
eval_node(const ast::job_list_t & job_list,const block_t * associated_block)1529 end_execution_reason_t parse_execution_context_t::eval_node(const ast::job_list_t &job_list,
1530                                                             const block_t *associated_block) {
1531     assert(associated_block && "Null block");
1532 
1533     // Check for infinite recursion: a function which immediately calls itself..
1534     wcstring func_name;
1535     if (const auto *infinite_recursive_node =
1536             this->infinite_recursive_statement_in_job_list(job_list, &func_name)) {
1537         // We have an infinite recursion.
1538         return this->report_error(STATUS_CMD_ERROR, *infinite_recursive_node,
1539                                   INFINITE_FUNC_RECURSION_ERR_MSG, func_name.c_str());
1540     }
1541 
1542     // Check for stack overflow. The TOP check ensures we only do this for function calls.
1543     if (associated_block->type() == block_type_t::top && parser->function_stack_is_overflowing()) {
1544         return this->report_error(STATUS_CMD_ERROR, job_list, CALL_STACK_LIMIT_EXCEEDED_ERR_MSG);
1545     }
1546     return this->run_job_list(job_list, associated_block);
1547 }
1548 
line_offset_of_node(const ast::job_t * node)1549 int parse_execution_context_t::line_offset_of_node(const ast::job_t *node) {
1550     // If we're not executing anything, return -1.
1551     if (!node) {
1552         return -1;
1553     }
1554 
1555     // If for some reason we're executing a node without source, return -1.
1556     auto range = node->try_source_range();
1557     if (!range) {
1558         return -1;
1559     }
1560 
1561     return this->line_offset_of_character_at_offset(range->start);
1562 }
1563 
line_offset_of_character_at_offset(size_t offset)1564 int parse_execution_context_t::line_offset_of_character_at_offset(size_t offset) {
1565     // Count the number of newlines, leveraging our cache.
1566     assert(offset <= pstree->src.size());
1567 
1568     // Easy hack to handle 0.
1569     if (offset == 0) {
1570         return 0;
1571     }
1572 
1573     // We want to return (one plus) the number of newlines at offsets less than the given offset.
1574     // cached_lineno_count is the number of newlines at indexes less than cached_lineno_offset.
1575     const wchar_t *str = pstree->src.c_str();
1576     if (offset > cached_lineno_offset) {
1577         size_t i;
1578         for (i = cached_lineno_offset; i < offset && str[i] != L'\0'; i++) {
1579             // Add one for every newline we find in the range [cached_lineno_offset, offset).
1580             if (str[i] == L'\n') {
1581                 cached_lineno_count++;
1582             }
1583         }
1584         cached_lineno_offset =
1585             i;  // note: i, not offset, in case offset is beyond the length of the string
1586     } else if (offset < cached_lineno_offset) {
1587         // Subtract one for every newline we find in the range [offset, cached_lineno_offset).
1588         for (size_t i = offset; i < cached_lineno_offset; i++) {
1589             if (str[i] == L'\n') {
1590                 cached_lineno_count--;
1591             }
1592         }
1593         cached_lineno_offset = offset;
1594     }
1595     return cached_lineno_count;
1596 }
1597 
get_current_line_number()1598 int parse_execution_context_t::get_current_line_number() {
1599     int line_number = -1;
1600     int line_offset = this->line_offset_of_node(this->executing_job_node);
1601     if (line_offset >= 0) {
1602         // The offset is 0 based; the number is 1 based.
1603         line_number = line_offset + 1;
1604     }
1605     return line_number;
1606 }
1607 
get_current_source_offset() const1608 int parse_execution_context_t::get_current_source_offset() const {
1609     int result = -1;
1610     if (executing_job_node) {
1611         if (auto range = executing_job_node->try_source_range()) {
1612             result = static_cast<int>(range->start);
1613         }
1614     }
1615     return result;
1616 }
1617