Closed zzamboni closed 2 years ago
@zzamboni, You should be a test engineer. Note that your reproduction only affects interactive shells. The non-interactive equivalent behaves as expected; i.e., no panic.
> ./elvish -c 'try { use bad } except x { put WTF $x }
bad:x'
▶ WTF
▶ [&reason=<unknown parse error: 25-25 in /Users/krader/.elvish/lib/bad.elv: should be ']'>]
Exception: exec: "bad:x": executable file not found in $PATH
code from -c, line 2: bad:x
Exception: ./elvish exited with 2
[tty 224], line 1-2: ./elvish -c 'try { use bad } except x { put WTF $x }
bad:x'
TBD is why the interactive context mutates the global list of namespaces to include an invalid module while the non-interactive context does not.
@krader1961 interesting. With an example like yours, it indeed does not crash:
> elvish -c 'try { use test } except e { put $e }; test:x'
▶ [&reason=<unknown compilation error: 4-11 in /Users/taazadi1/.elvish/lib/test.elv: variable $foobar not found>]
Exception: exec: "test:x": executable file not found in $PATH
code from -c, line 1: try { use test } except e { put $e }; test:x
Exception: elvish exited with 2
[tty 2], line 1: elvish -c 'try { use test } except e { put $e }; test:x'
However, if I don't use try
/except
, I still get the crash even noninteractively:
> elvish -c 'e = ?(use test); put $e
test:x'
▶ [&reason=<unknown compilation error: 4-11 in /Users/taazadi1/.elvish/lib/test.elv: variable $foobar not found>]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x1255ee6]
goroutine 28 [running]:
src.elv.sh/pkg/eval.(*Ns).lookup(0x0, 0xc0000a90d5, 0x2, 0xc0000a49d8)
src.elv.sh/pkg/eval/ns.go:101 +0x26
src.elv.sh/pkg/eval.(*Ns).IndexName(...)
src.elv.sh/pkg/eval/ns.go:93
src.elv.sh/pkg/eval.deref(0xc0001be700, 0xc00008dbf0, 0xc000072ac0, 0x10cfb19)
src.elv.sh/pkg/eval/var_ref.go:135 +0xd5
src.elv.sh/pkg/eval.variableOp.exec(0x18, 0x1e, 0x0, 0xc0000a90d7, 0x7, 0xc00008dbf0, 0xc0001be700, 0xc0000fdf70, 0x8, 0x1, ...)
src.elv.sh/pkg/eval/compile_value.go:317 +0x4d
src.elv.sh/pkg/eval.evalForValue(0xc0001be700, 0x13b9bb8, 0xc00008dc20, 0x135abe2, 0x7, 0x7ffeefbff8c2, 0x4, 0xc0001c44d0, 0x1262ee5)
src.elv.sh/pkg/eval/compile_value.go:577 +0x48
src.elv.sh/pkg/eval.evalForCommand(0xc0001be700, 0x13b9bb8, 0xc00008dc20, 0x135abe2, 0x7, 0x0, 0x0, 0x0, 0x0)
src.elv.sh/pkg/eval/compile_effect.go:384 +0x74
src.elv.sh/pkg/eval.(*formOp).exec(0xc0000ae9a0, 0xc0001be700, 0x0, 0x0)
src.elv.sh/pkg/eval/compile_effect.go:346 +0x609
src.elv.sh/pkg/eval.(*pipelineOp).exec.func1(0x13b7448, 0xc0000ae9a0, 0xc0001be700, 0xc0001ca030, 0xc0000a9150, 0x203000)
src.elv.sh/pkg/eval/compile_effect.go:117 +0x3f
created by src.elv.sh/pkg/eval.(*pipelineOp).exec
src.elv.sh/pkg/eval/compile_effect.go:116 +0x225
Exception: elvish exited with 2
[tty 1], line 1-2: elvish -c 'e = ?(use test); put $e
test:x'
Hmm, the behavior is specific to interactive shells because a failed import would cause an exception and abort the surrounding block. In non-interactive cases this would normally cause the surrounding namespace to become inaccessible, so the broken variable doesn't matter (unless the exception is swallowed by ?()
; you can construct a similar repro with it in a non-interactive script). The interactive case is different as the REPL will still pick up the broken variable.
I'll need to think a bit about how to best handle this.
I'll need to think a bit about how to best handle this.
I spent a couple of hours using my (unmerged) trace package to understand the dynamics of this unexpected behavior in the hope I could identify an obvious fix. I failed to find a simple fix. ☹️
It's not clear this should be a blocking bug for the next point release. All bugs should be fixed ASAP but this is primarily a UI bug that few people (close to zero in my estimation) will ever notice.
Not entirely sure if relevant, but I can trigger a crash in the same function (src.elv.sh/pkg/eval.(*Ns).lookup
) by doing the following:
str:split "abc" "b"
fail; use str # it appears necessary that the line fails in which an import is performed
Use the up arrow key twice to cycle back to the "str:split" command.
I can reliably reproduce a SIGSEGV panic with the following backtrace on df3e7a9268435d96b4432b517784e1358575ae3b:
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x2 addr=0x20 pc=0x100f619c0]
goroutine 4591 [running]:
src.elv.sh/pkg/eval.(*Ns).lookup(0x0, 0x14000339cf8, 0x6, 0x6)
/Users/jannis/src/github.com/elves/elvish/pkg/eval/ns.go:100 +0x20
src.elv.sh/pkg/eval.(*Ns).IndexName(...)
/Users/jannis/src/github.com/elves/elvish/pkg/eval/ns.go:92
src.elv.sh/pkg/eval.(*Ns).Index(0x0, 0x1010458a0, 0x14000339d18, 0x100fb7ffd, 0x1, 0x14000339cf8)
/Users/jannis/src/github.com/elves/elvish/pkg/eval/ns.go:80 +0x50
src.elv.sh/pkg/edit.hasFn(0x0, 0x1400015dc24, 0x5, 0x1)
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight.go:93 +0x7c
src.elv.sh/pkg/edit.hasQualifiedFn(0x1400015f450, 0x1400015dc20, 0x4, 0x1400015dc24, 0x5, 0x5)
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight.go:89 +0x16c
src.elv.sh/pkg/edit.hasCommand(0x1400015f450, 0x1400015dc20, 0x9, 0x14000235ec0)
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight.go:54 +0xe0
src.elv.sh/pkg/edit.initHighlighter.func2(0x1400015dc20, 0x9, 0x8)
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight.go:17 +0x38
src.elv.sh/pkg/edit/highlight.highlight.func1(0x14000235d80, 0x5, 0x8, 0x1400028c318, 0x1, 0x1, 0x14000189e80, 0x14000189e90, 0x14
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight/highlight.go:104 +0xac
created by src.elv.sh/pkg/edit/highlight.highlight
/Users/jannis/src/github.com/elves/elvish/pkg/edit/highlight/highlight.go:100 +0x858
I can reproduce the panic described by @Xjs.
[~]|> elvish -buildinfo
Version: v0.16.0-dev.df3e7a9268435d96b4432b517784e1358575ae3b
Go version: go1.16.3
Reproducible build: true
I found a new (?) way to crash elvish. I think it might have the same underlying cause as the present issue, so I post it here instead of opening a new one.
To reproduce, follow this transcript:
⬥ var z:
⬥ eval &on-end=[ns]{ set z: = $ns } 'will not compile }'
Exception: parse error: unexpected rune '}'
[eval 3], line 1: will not compile }
[tty 3], line 1: eval &on-end=[ns]{ set z: = $ns } 'will not compile }'
⬥ put $z:
⮕ <ns 0x0>
That 0x0
made me suspect I can trick elvish into accessing a null pointer. And so I can:
⬥ put $z:⟨TAB⟩
goroutine 1 [running]:
src.elv.sh/pkg/sys.DumpStack(0x140005b6518, 0x103053e00)
src.elv.sh/pkg/sys/dumpstack.go:10 +0x8c
src.elv.sh/pkg/shell.handlePanic()
src.elv.sh/pkg/shell/interact.go:142 +0x5c
panic(0x103053e00, 0x1032beda0)
runtime/panic.go:965 +0x14c
src.elv.sh/pkg/eval.(*Ns).IterateNames(0x0, 0x14000302100)
src.elv.sh/pkg/eval/ns.go:124 +0x20
src.elv.sh/pkg/edit.eachVariableInTop(0x140001a05a0, 0x1400055b4f0, 0x1400042d075, 0x2, 0x14000302100)
src.elv.sh/pkg/edit/ns_helper.go:41 +0x1e4
src.elv.sh/pkg/edit.pureEvaler.EachVariableInNs(0x140000d8f70, 0x1400042d075, 0x2, 0x14000302100)
src.elv.sh/pkg/edit/completion.go:541 +0x60
src.elv.sh/pkg/edit/complete.completeVariable(0x1030d0c50, 0x14000532240, 0x1030d4978, 0x140000d8f70, 0x14000350150, 0x14000168020, 0x0, 0x0, 0x0, 0x0, ...)
src.elv.sh/pkg/edit/complete/completers.go:198 +0x1b4
src.elv.sh/pkg/edit/complete.Complete(0x1400042d070, 0x7, 0x7, 0x1030d4978, 0x140000d8f70, 0x14000350150, 0x14000168020, 0x0, 0x0, 0x6)
src.elv.sh/pkg/edit/complete/complete.go:92 +0x174
src.elv.sh/pkg/edit.completionStart(0x1030d56d8, 0x14000120000, 0x1030ca408, 0x14000114c00, 0x1030d4978, 0x140000d8f70, 0x14000350150, 0x14000168020, 0x140005b6d01)
src.elv.sh/pkg/edit/completion.go:164 +0xa4
src.elv.sh/pkg/edit.initCompletion.func4()
src.elv.sh/pkg/edit/completion.go:249 +0x98
reflect.Value.call(0x1030311c0, 0x14000114c30, 0x13, 0x102f95037, 0x4, 0x0, 0x0, 0x0, 0x140005b7038, 0x102cc0220, ...)
reflect/value.go:476 +0x650
reflect.Value.Call(0x1030311c0, 0x14000114c30, 0x13, 0x0, 0x0, 0x0, 0x12, 0x1034785e0, 0x140005b7038)
reflect/value.go:337 +0x84
src.elv.sh/pkg/eval.(*goFn).Call(0x140001261c0, 0x1400040e000, 0x0, 0x0, 0x0, 0x14000182780, 0x1400012c000, 0x3)
src.elv.sh/pkg/eval/go_fn.go:227 +0x530
src.elv.sh/pkg/eval.(*Evaler).Call(0x140000d8f70, 0x1030c9ba8, 0x140001261c0, 0x0, 0x0, 0x0, 0x14000182780, 0x102f99961, 0x10, 0x1400012c000, ...)
src.elv.sh/pkg/eval/eval.go:491 +0x190
src.elv.sh/pkg/edit.callWithNotifyPorts(0x1030cc1a8, 0x1400009e900, 0x140000d8f70, 0x1030c9ba8, 0x140001261c0, 0x0, 0x0, 0x0)
src.elv.sh/pkg/edit/key_binding.go:67 +0x130
src.elv.sh/pkg/edit.mapBindings.Handle(0x1030cc1a8, 0x1400009e900, 0x140000d8f70, 0x140000b0c18, 0x1, 0x1, 0x1030cc108, 0x14000122000, 0x1030ca2c8, 0x1400042c030, ...)
src.elv.sh/pkg/edit/key_binding.go:41 +0x17c
src.elv.sh/pkg/cli/tk.(*codeArea).handleKeyEvent(0x14000122000, 0x10000000009, 0x14000120000)
src.elv.sh/pkg/cli/tk/codearea.go:289 +0xec
src.elv.sh/pkg/cli/tk.(*codeArea).Handle(0x14000122000, 0x1030ca2c8, 0x1400042c008, 0x1030ca201)
src.elv.sh/pkg/cli/tk/codearea.go:164 +0xcc
src.elv.sh/pkg/cli/mode.(*histwalk).Handle(0x140007f40a0, 0x1030ca2c8, 0x1400042c008, 0x0)
src.elv.sh/pkg/cli/mode/histwalk.go:52 +0xd0
src.elv.sh/pkg/cli.(*app).handle(0x14000120000, 0x10307d020, 0x1400042c008)
src.elv.sh/pkg/cli/app.go:196 +0x1c8
src.elv.sh/pkg/cli.(*loop).Run(0x1400011e000, 0x1400008c101, 0x140001cc5a0, 0x14000120000, 0x14000596290)
src.elv.sh/pkg/cli/loop.go:129 +0x100
src.elv.sh/pkg/cli.(*app).ReadCode(0x14000120000, 0x0, 0x0, 0x0, 0x0)
src.elv.sh/pkg/cli/app.go:365 +0x35c
src.elv.sh/pkg/edit.(*Editor).ReadCode(0x1400009e900, 0x1400009c010, 0x7, 0x1400042d070, 0x7)
src.elv.sh/pkg/edit/editor.go:108 +0x34
src.elv.sh/pkg/shell.interact(0x140000d8f70, 0x1400009c000, 0x1400009c008, 0x1400009c010, 0x1400018bd98)
src.elv.sh/pkg/shell/interact.go:99 +0x32c
src.elv.sh/pkg/shell.Program.Run(0x1030c0ac8, 0x1400009c000, 0x1400009c008, 0x1400009c010, 0x14000198080, 0x1400008e1d0, 0x0, 0x0, 0x0, 0x0)
src.elv.sh/pkg/shell/shell.go:79 +0xf8
src.elv.sh/pkg/prog.Run(0x1400009c000, 0x1400009c008, 0x1400009c010, 0x1400008e1d0, 0x1, 0x1, 0x1400018bf38, 0x3, 0x3, 0x0)
src.elv.sh/pkg/prog/prog.go:142 +0x298
main.main()
src.elv.sh/cmd/elvish/main.go:18 +0xf8
goroutine 33 [chan receive, 3 minutes]:
src.elv.sh/pkg/eval.getBlackholeChan.func1(0x140001cc0c0)
src.elv.sh/pkg/eval/port.go:96 +0x3c
created by src.elv.sh/pkg/eval.getBlackholeChan
src.elv.sh/pkg/eval/port.go:95 +0x50
goroutine 34 [syscall]:
os/signal.signal_recv(0x1030cc9f0)
runtime/sigqueue.go:165 +0xc4
os/signal.loop()
os/signal/signal_unix.go:23 +0x20
created by os/signal.Notify.func1.1
os/signal/signal.go:151 +0x44
goroutine 19 [chan receive]:
src.elv.sh/pkg/shell.initTTYAndSignal.func1(0x14000180300, 0x1030c9948, 0x1400009c010)
src.elv.sh/pkg/shell/shell.go:130 +0x90
created by src.elv.sh/pkg/shell.initTTYAndSignal
src.elv.sh/pkg/shell/shell.go:129 +0x64
goroutine 21 [chan receive]:
src.elv.sh/pkg/cli/prompt.(*Prompt).loop(0x140000d0d20)
src.elv.sh/pkg/cli/prompt/prompt.go:77 +0xa0
created by src.elv.sh/pkg/cli/prompt.New
src.elv.sh/pkg/cli/prompt/prompt.go:70 +0x154
goroutine 22 [chan receive]:
src.elv.sh/pkg/cli/prompt.(*Prompt).loop(0x140000d0e00)
src.elv.sh/pkg/cli/prompt/prompt.go:77 +0xa0
created by src.elv.sh/pkg/cli/prompt.New
src.elv.sh/pkg/cli/prompt/prompt.go:70 +0x154
runtime error: invalid memory address or nil pointer dereference
If a
use
d module contains an error, Elvish crashes upon any attempt at accessing its namespace.For example, if
~/.elvish/lib/test.elv
contains the following:Then:
Now I type
test:
followed byt
(any other key works too), Elvish panics the moment I type the key following the colon:Trying again, now I type
test:
followed by Tab, which produces a longer backtrace: