Commit Graph

147 Commits

Author SHA1 Message Date
Mahmoud Al-Qudsi
e01eb2e615 Add proper way of storing value for status current-command
There should be no functional changes in this commit.

The global variable `$_` set in the parser variables by `reader.cpp` and
read by the `status` builtin was deprecated in fish 2.0 but kept around
internally because there's no good way to store/share/forward parser
variables.

A new enum is added that identifies the status variable and they are
stored in a private array in the parser. There is no need for
synchronization because they are only set during job init and never
thereafter. This is currently asserted via ASSERT_IS_MAIN_THREAD() but
that assert can be dropped in the interest of making the parser possible
to clone and use from worker threads.

The old `$_` global variable is still kept for backwards compatibility,
though it will be dropped in a future release.
2022-10-26 12:15:02 -05:00
Mahmoud Al-Qudsi
175caab583 Prevent stack overflow from eval/substitution recursion
It seems to have originally been thought that the only possible way a stack
overflow could happen is via function calls, but there are other possibilities.

Issue #9302 reports how `eval` can be abused to recursively execute a string
substitution ad infinitum, triggering a stack overflow in fish.

This patch extends the stack overflow check to also check the current
`eval_level` against a new constant `FISH_MAX_EVAL_DEPTH`, currently set to a
conservative but hopefully still fair limit of 500. For future reference, with
the default stack size for the main/foreground thread of 8 MiB, we actually have
room for a stack depth around 2800, but that's only with extremely minimal state
stored in each stack frame.

I'm not entirely sure why we don't check `eval_depth` regardless of block type;
it can't be for performance reasons since it's just a simple integer comparison
- and a ridiculously easily one for the branch predictor handle, at that - but
maybe it's to try and support non-recursive nested execution blocks of greater
than `FISH_MAX_STACK_DEPTH`? But even without recursion, the stack can still
overflow so may be we should just bump the limit up some (to 500 like the new
`FISH_MAX_EVAL_DEPTH`?) and check it all the time?

Closes #9302.
2022-10-25 13:40:21 -05:00
Mahmoud Al-Qudsi
e7bf98adc1 Make block_t moveable
The presence of the explicit constructor (even though it did nothing) prevented
the compiler from generating a move constructor for `block_t`.
2022-10-24 22:06:30 -05:00
Mahmoud Al-Qudsi
84b53b4cae Significantly reduce size of block_t
A `block_t` instance is allocated for each live block type in memory when
executing a script or snippet of fish code. While many of the items in a
`block_t` class are specific to a particular type of block, the overhead of
`maybe_t<event_t>` that's unused except in the relatively extremely rare case of
an event block is more significant than the rest, given that 88 out of the 216
bytes of a `block_t` are set aside for this field that is rarely used.

This patch reorders the `block_t` members by order of decreasing alignment,
bringing down the size to 208 bytes, then changes `maybe_t<event_t>` to
`shared_ptr<event_t>` instead of allocating room for the event on the stack.
This brings down the runtime memory size of a `block_t` to 136 bytes for a 37%
reduction in size.

I would like to investigate using inheritance and virtual methods to have a
`block_t` only include the values that actually make sense for the block rather
than always allocating some sort of storage for them and then only sometimes
using it. In addition to further reducing the memory, I think this could also be
a safer and saner approach overall, as it would make it very clear when and
where we can expect each block_type_type_t-dependent member to be present and
hold a value.
2022-10-24 21:04:17 -05:00
Aaron Gyes
14d2a6d8ff IWYU-guided #include rejiggering.
Let's hope this doesn't causes build failures for e.g. musl: I just
know it's good on macOS and our Linux CI.

It's been a long time.

One fix this brings, is I discovered we #include assert.h or cassert
in a lot of places. If those ever happen to be in a file that doesn't
include common.h, or we are before common.h gets included, we're
unawaringly working with the system 'assert' macro again, which
may get disabled for debug builds or at least has different
behavior on crash. We undef 'assert' and redefine it in common.h.

Those were all eliminated, except in one catch-22 spot for
maybe.h: it can't include common.h. A fix might be to
make a fish_assert.h that *usually* common.h exports.
2022-08-20 23:55:18 -07:00
ridiculousfish
082f074bb1 Switch filenames from intern'd strings to shared_ptr
We store filenames in function definitions to indicate where the
function comes from. Previously these were intern'd strings. Switch them
to a shared_ptr<wcstring>, intending to remove intern'd strings.
2022-08-13 12:51:36 -07:00
ridiculousfish
0230420983 Stop initializing principal parser at global scope
Avoid the risk of global constructors by making this a function-level
static.
2022-06-20 12:31:36 -07:00
ridiculousfish
50f6b06251 Replace a bunch of ASSERT_IS_MAIN_THREAD
Switch these to a new function parser.assert_can_execute(), in
preparation for allowing execution off of the main thread.
2022-06-20 12:31:36 -07:00
ridiculousfish
f45e16e59d Try to rationalize universal variable syncing
Prior to this commit, setting a universal variable may trigger syncing
against the file which will modify other universal variables. But if we
want to support multiple environments we need the parser to decide when to
sync uvars. Shift the decision of when to sync to the parser itself. When a
universal variable is modified, now we just set a flag and it's up to the
(main) parser when to pick it up. This is hopefully just a refactoring with
no user-visible changes.
2022-05-30 14:09:06 -07:00
Aaron Gyes
0118eafee1 Remove unused functions, members (and a variable)
If we ever need any of these... they're in this commit:

fish_wcswidth_visible()
status_cmd_opts_t::feature_name
completion_t::is_naturally_less_than()
parser_t::set_empty_var_and_fire()
parser_t::get_block_desc()
parser_keywords_skip_arguments()
parser_keywords_is_block()
job_t::has_internal_proc()
fish_wcswidth_visible()
2022-04-09 10:10:44 -07:00
ridiculousfish
ac888ac6af Migrate 'within_fish_init' to a parser-local variable
We need special handling when reporting backtraces for commands run
during startup, i.e. config.fish. Previously we had a global variable;
make it local to the parser to eliminate a global.

No functional change here.
2022-03-24 21:43:58 -07:00
ridiculousfish
1763e7d3bc Remove some dead code
These functions were unused.
2022-03-20 14:48:44 -07:00
ridiculousfish
0c06ca3c3f Mark parser_t::principal as const 2021-09-24 21:09:28 -07:00
Rosen Penev
90f006b1cd clang-tidy: use delete
The clang warning for pending_signals_t was about the operator=
return type being wrong (misc-unconventional-assign-operator).

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-08-20 01:33:33 +02:00
ridiculousfish
2ca66cff53 Disable job control inside command substitutions
This disables job control inside command substitutions. Prior to this
change, a cmdsub might get its own process group. This caused it to fail
to cancel loops properly. For example:

    while true ; echo (sleep 5) ; end

could not be control-C cancelled, because the signal would go to sleep,
and so the loop would continue on. The simplest way to fix this is to
match other shells and not use job control in cmdsubs.

Related is #1362
2021-08-18 22:20:03 +08:00
ridiculousfish
32e23c84f4 Clean up parser_t::push_block
Fix some unnecessary copying and unused variables.
2021-07-28 15:37:34 -07:00
ridiculousfish
789261a40c Stop storing is_breakpoint inside the parser
This can also be trivially computed from the block list.
2021-07-28 13:56:33 -07:00
ridiculousfish
b914c94cc1 Stop storing 'is_block' inside the parser
is_block is a field which supports 'status is-block', and also controls
whether notifications get posted. However there is no reason to store
this as a distinct field since it is trivially computed from the block
list. Stop storing it. No functional changes in this commit.
2021-07-28 13:56:33 -07:00
ridiculousfish
938879a85a Remove a stale comment and add a missing initializer 2021-07-23 11:22:45 -07:00
ridiculousfish
ccd1b4e4f4 Clean up of get_function_name
Have it return a real string, instead of a pointer with uncertain
lifetime.
2021-07-15 11:36:43 -07:00
ridiculousfish
bad1b84513 Remove the index parameter from parser_t::is_function
It was always 0 in practice.
2021-07-15 11:04:06 -07:00
ridiculousfish
82fd8fe9fb Refactor wait handles
In preparation for using wait handles in --on-process-exit events, factor
wait handles into their own wait handle store. Also switch them to
per-process instead of per-job, which is a simplification.
2021-05-17 15:25:21 -07:00
ridiculousfish
632e150152 Introduce notion of "wait handles"
This is preparing to address the problem where fish cannot wait on a
reaped job, because it only looks at the active job list. Introduce the
idea of a "wait handle," which is a thing that `wait` can use to check if
a job is finished. A job may produce its wait handle on demand, and
parser_t will save the wait handle from wait-able jobs at the point they
are reaped.

This change merely introduces the idea; the next change makes builtin_wait
start using it.
2021-05-15 20:20:50 -07:00
ridiculousfish
aeabc76b2e Use internal job ids in builtin_wait
This avoids any potential issues due to recycled job IDs.
No user visible change.
2021-05-13 12:11:00 -07:00
Fabian Homborg
594d51e7eb Add a separate --profile-startup option to profile startup
This goes to a separate file because that makes option parsing easier
and allows profiling both at the same time.

The "normal" profile now contains only the profile data of the actual
run, which is much more useful - you can now profile a function by
running

   fish -C 'source /path/to/thing' --profile /tmp/thefunction.prof -c 'thefunction'

and won't need to filter out extraneous information.
2021-01-29 20:46:34 +01:00
Johannes Altmanninger
45e7c709f4 Consolidate complete cycle detection and always report error on cycle
Detect recursive calls to builtin complete and the internal completion in
the same place.

In 0a0149cc2 (Prevent infinite recursion when completion wraps variable assignment)
we don't print an error when completing certain aliases like:

	alias vim "A=B vim"

But we also gave no completions.
We could make this case work, but I think that trying to salvage situations
like this one is way too complex. Instead, let the user know by printing an
error. Not sure if the style of the error fits.

We could add some heuristic to alias to not add --wraps in some cyclic cases.
2020-09-26 14:56:03 +02:00
Fabian Homborg
30b2dc2b97 Don't enqueue a repaint in the middle of one
This can easily lead to an infinite loop, if a variable handler
triggers a repaint and the variable is set in the prompt, e.g. some of
the git variables.

A simple way to reproduce:

    function fish_mode_prompt
        commandline -f repaint
    end

Repainting executes the mode prompt, which triggers a repaint, which
triggers the mode prompt, ....

So we just set a flag and check it.

Fixes #7324.
2020-09-11 19:23:26 +02:00
ridiculousfish
b0182183d4 Rework exit command
Prior to this fix, the `exit` command would set a global variable in the
reader, which parse_execution would check. However in concurrent mode you
may have multiple scripts being sourced at once, and 'exit' should only
apply to the current script.

Switch to using a variable in the parser's libdata instead.
2020-08-15 16:06:54 -07:00
Soumya
a2b2bcef6e Add a $status_generation variable that's incremented for each interactive command that produces a status.
This can be used to determine whether the previous command produced a real status, or just carried over the status from the command before it. Backgrounded commands and variable assignments will not increment status_generation, all other commands will.
2020-08-05 12:23:49 -07:00
ridiculousfish
bae64f8a8a Modest cleanup of profiling
This is a set of miscellaneous cleanup for profiling.

An errant newline has been removed from 'if' statement output, which got
introduced with the new ast.
Switch from storing unique_ptr to a deque, which allocates less.
Collapse "parse" and "exec" times into just a single value "duration". The
"parse" time no longer makes sense, as we now parse ahead of time.
2020-07-24 11:53:07 -07:00
ridiculousfish
dff4f140b0 Make the list of blocked events const
These are events that have been queued but not yet fired. There's no
reason to modify the events after creating them. Mark them as const
to ensure that doesn't happen.
2020-07-19 12:03:10 -07:00
ridiculousfish
9ee5075fc3 Reformat CPP files 2020-07-12 12:21:25 -07:00
ridiculousfish
2a4c545b21 Rework how signals trigger cancellation
When fish receives a "cancellation inducing" signal (SIGINT in particular)
it has to unwind execution - for example while loops or whatever else that
is executing. There are two ways this may come about:

1. The fish process received the signal
2. A child process received the signal

An example of the second case is:

    some_command | some_function

Here `some_command` is the tty owner and so will receive control-C, but
then fish has to cancel function execution.

Prior to this change, these were handled uniformly: both would just set a
cancellation signal inside the parser. However in the future we will have
multiple parsers and it may not be obvious which one to set the flag in.
So instead distinguish these cases: if a process receives SIGINT we mark
the signal in its job group, and if fish receives it we set a global
variable.
2020-07-12 12:16:01 -07:00
ridiculousfish
3534c07584 Adopt the new AST in parse_execution
parse_execution is what turns a parsed tree into jobs, etc. Switch it from
parse_tree to the new AST.
2020-07-04 14:58:05 -07:00
ridiculousfish
7cc99a2d80 Rename job_tree to job_group
Initially I wanted to pick a different name to avoid confusion with
process groups, but really job trees *are* process groups. So name them
to reflect that fact.

Also rename "placeholder" to "internal" which is clearer.
2020-05-30 14:22:44 -07:00
ridiculousfish
a86d3f4136 Remove job_lineage_t
Its responsibilities are now subsumed by job_tree_t except for
the block_io which we pass around explicitly.
2020-05-30 14:22:44 -07:00
ridiculousfish
e95bcfb074 Teach a job to decide its job tree
Job trees come in two flavors: “placeholders” for jobs which are only fish
functions, and non-placeholders which need to track a pgid. This adds
logic to allow a job to decide if its parent's job tree is appropriate,
and allocating a new tree if not.
2020-05-30 14:22:43 -07:00
ridiculousfish
938b683895 Thread pgroups into command substitutions
Give string expansion an (optional) parent pgroup. This is threaded all
the way into eval(). This ensures that in a mixed pipeline like:

   cmd | begin ; something (cmd2) ; end

that cmd2 and cmd have the same pgroup.

Add a test to ensure that command substitutions inherit pgroups
properly.

Fixes #6624
2020-04-26 11:05:50 -07:00
ridiculousfish
5886b961d8 Send events more often for variable sets outside of builtin_set
When changing certain variables programmatically, ensure that events
are sent. Fixes #6653
2020-03-08 23:28:37 -07:00
ridiculousfish
bc702ccb31 Fix interactive --on-signal INT handlers
f8ba0ac5bf introduced a bug where INT handlers would themselves be
cancelled, due to the signal. Defer processing handlers until the
parser is ready to execute more fish script.

Fixes the interactive case of #6649.
2020-03-01 13:31:59 -08:00
ridiculousfish
6bf9ae9aeb Fix up --on-job-exit caller
The `function --on-job-exit caller` feature allows a command substitution
to observe when the parent job exits. This has never worked very well - in
particular it is based on job IDs, so a function that observes this will
run multiple times. Implement it properly.

Do this by having a not-recycled "internal job id".

This is only used by psub, but ensure it works properly none-the-less.
2020-02-08 16:23:25 -08:00
ridiculousfish
fba3c83ba5 Eliminate yet more calls to principal_parser()
In particular, remove job_t::from_job_id
2020-02-08 12:47:13 -08:00
ridiculousfish
38f4330683 Rationalize $status and errors
Prior to this fix, fish was rather inconsistent in when $status gets set
in response to an error. For example, a failed expansion like "$foo["
would not modify $status.

This makes the following inter-related changes:

1. String expansion now directly returns the value to set for $status on
error. The value is always used.

2. parser_t::eval() now directly returns the proc_status_t, which cleans
up a lot of call sites.

3. We expose a new function exec_subshell_for_expand() which ignores
$status but returns errors specifically related to subshell expansion.

4. We reify the notion of "expansion breaking" errors. These include
command-not-found, expand syntax errors, and others.

The upshot is we are more consistent about always setting $status on
errors.
2020-01-25 17:28:41 -08:00
ridiculousfish
81e78c78aa Rename eval_result_t to end_execution_reason_t
We're getting ready to stop returning eval_result_t from parser_t::eval
2020-01-25 14:11:32 -08:00
ridiculousfish
0f7bba5f0e Introduce operation_context_t
This commit recognizes an existing pattern: many operations need some
combination of a set of variables, a way to detect cancellation, and
sometimes a parser. For example, tab completion needs a parser to execute
custom completions, the variable set, should cancel on SIGINT. Background
autosuggestions don't need a parser, but they do need the variables and
should cancel if the user types something new. Etc.

This introduces a new triple operation_context_t that wraps these concepts
up. This simplifies many method signatures and argument passing.
2020-01-16 15:21:28 -08:00
ridiculousfish
4bb18eaf42 Use completion_list_t naming everywhere
std::vector<completion_t> -> completion_list_t
2020-01-16 15:18:49 -08:00
ridiculousfish
7e1270ae70 Be more disciplined about cancellation signals
Rather than storing a "should cancel" flag in the parser, store the
actual signal which triggered cancellation.
2020-01-14 15:20:04 -08:00
Rosen Penev
06cb0bbe9a
[clang-tidy] Add several references
Found with performance-unnecessary-value-param

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2019-12-26 21:55:53 -08:00
ridiculousfish
c19407ab0f Default parser_t::eval()'s block type to top
This is the parameter value at every call site except one. Just make it the
default.
2019-12-22 16:27:03 -08:00
ridiculousfish
0c49dce75d Factor block description part of stack traces into a new function 2019-12-22 16:22:20 -08:00