nushell: Nushell thread panics if a variable is passed to a custom command that contains a recursive call to itself.
Describe the bug
In the REPL of Nushell, if you try to send any variable to a custom command that uses recursion to call itself, the Nushell executable will thread panic as soon as you type enough of the custom command’s name to make it disticnt. However, if you pass the exact same value as a literal it works normally. This does not happen if you embed the custom command inside a Nu script or if you call nu with using the ‘-c’ flag.
Attempting to fool Nu by disguising the variable in a direct call to a simple closure it will still panic. Also, if you create another custom command that refers to the global variable and returns it, the Nu reader still panics. Local variables that are then returned work normally. Only global variables that are passed to bad custom command cause Nu to panic.
How to reproduce
- Create a custom command that accepts input., and recursively calls itself with that input.
- Create a variable that contains some value of any type.
- I used a simple int.
- In the REPL of Nu, try and type a pipeline passing the dereference of that variable to the custom command.
- As soon as you type enough of the command’s name that it is distinct, nu thread panics.
Here is a sample command that will trigger the panic:
# This command does nothing but countdown to 0 and returns false.
def px [n=0] {
let l = $in
if $n == 0 { return false } else {
$l | px ($n - 1)
}
}
Sammple session in the REPL
minerva issues.nushell >> > source px.nu
minerva issues.nushell >> > 1 | px 3
false
minerva issues.nushell >> > let x = 1
minerva issues.nushell >> > $x | pthread 'main' panicked at 'Attempt to mutate a block that is in the permanent (immutable) state', /Users/edhowland/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nu-protocol-0.85.0/src/engine/engine_state.rs:1789:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$
… back in Bash.
Note the following working steps
mini issues.nushellnu -c "source px.nu; let x = 1; $x | px 3"
false
Or running from a .nu script:
# t-px.nu: Attempt to trigger the panic from a script
source px.nu
let x = 1
$x | px 3
Then run it:
These examples all work as intended.
This only triggers the panic with global variables.
Local variables in a block or in another custom command or closure will not
trigger the panic.
```nu
minerva issues.nushell >> > source px.nu
minerva issues.nushell >> > if true {
::: let x = 1
::: $x
::: } | px 3
false
minerva issues.nushell >> > do {|y| $y } 2 | px 3
false
minerva issues.nushell >> > def foo [] {
::: let z = 1
::: $z
::: }
minerva issues.nushell >> > foo | px 3
false
But, using a global variable in the above examples will trigger the panic.
```nu
minerva issues.nushell >> > open foo.nu
source px.nu
let x = 1
def foo [] {
$x
}
minerva issues.nushell >> > source foo.nu
minerva issues.nushell >> > foo | pthread 'main' panicked at 'Attempt to mutate a block that is in the permanent (immutable) state', /Users/edhowland/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nu-protocol-0.85.0/src/engine/engine_state.rs:1789:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Or with a simple closure: (also works with blocks:
minerva issues.nushell >> > source px.nu
minerva issues.nushell >> > let x = 1
minerva issues.nushell >> > do {|| $x } | pthread 'main' panicked at 'Attempt to mutate a block that is in the permanent (immutable) state', /Users/edhowland/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nu-protocol-0.85.0/src/engine/engine_state.rs:1789:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Expected behavior
you should be able to write a custom command in Nu that takes input from a pipeline and uses recursion to perform its job. This does work properly in most cases if the input to the command is either a local variable, from some earlier command that fetches/opens/generates output to feed to the command. You should be able to experiment with that command within the command line environment and if you use a literal value it works ok. You should be bale to store that literal value in a global variable so you do not have to retype it every time and then just dereference the global variable and pass it to the pipeline input. This latter use of a global variable triggers the hard panic.
Screenshots
minerva issues.nushell >> > source px.nu
minerva issues.nushell >> > let x = 1
minerva issues.nushell >> > $x | pthread ‘main’ panicked at ‘Attempt to mutate a block that is in the permanent (immutable) state’, /Users/edhowland/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nu-protocol-0.85.0/src/engine/engine_state.rs:1789:13
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
$
Configuration
| key | value |
|---|---|
| version | 0.85.0 |
| branch | |
| commit_hash | |
| build_os | macos-aarch64 |
| build_target | aarch64-apple-darwin |
| rust_version | rustc 1.72.0 (5680fa18f 2023-08-23) |
| rust_channel | stable-aarch64-apple-darwin |
| cargo_version | cargo 1.72.0 (103a7ff2e 2023-08-15) |
| build_time | 2023-10-02 09:52:38 -04:00 |
| build_rust_channel | release |
| allocator | mimalloc |
| features | default, sqlite, trash, which, zip |
| installed_plugins | query, query json, query web, query xml |
| key | value |
| ------------------ | --------------------------------------- |
| version | 0.85.0 |
| branch | |
| commit_hash | |
| build_os | macos-aarch64 |
| build_target | aarch64-apple-darwin |
| rust_version | rustc 1.72.0 (5680fa18f 2023-08-23) |
| rust_channel | stable-aarch64-apple-darwin |
| cargo_version | cargo 1.72.0 (103a7ff2e 2023-08-15) |
| build_time | 2023-10-02 09:52:38 -04:00 |
| build_rust_channel | release |
| allocator | mimalloc |
| features | default, sqlite, trash, which, zip |
| installed_plugins | query, query json, query web, query xml |
Additional context
Tried to get the backtrace as suggested by setting RUST_BACKTRACE=1 but I think that to do that I need to compile nu in debug mode first not in release mode.
About this issue
- Original URL
- State: closed
- Created 6 months ago
- Comments: 16 (7 by maintainers)
Tried to look into it, and found it doesn’t work with
$in, panic can happened if we have a recursive call.Here is a smaller reproducable example:
When type final
xin repl, nushell panic.