From 5550819ac00b26174edad68a374275fbd171bb53 Mon Sep 17 00:00:00 2001 From: Qi Xiao Date: Sun, 12 Jan 2020 00:42:18 +0000 Subject: [PATCH] pkg/eval: Check FD when using it as redir source. This fixes #788. --- pkg/eval/compile_effect.go | 11 +++++++-- pkg/eval/compile_effect_test.go | 40 +++++++++++++++++++++------------ pkg/eval/frame.go | 4 +++- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/pkg/eval/compile_effect.go b/pkg/eval/compile_effect.go index e934d50f..8e2027f8 100644 --- a/pkg/eval/compile_effect.go +++ b/pkg/eval/compile_effect.go @@ -478,6 +478,10 @@ type redirOp struct { flag int } +type invalidFD struct{ fd int } + +func (err invalidFD) Error() string { return fmt.Sprintf("invalid fd: %d", err.fd) } + func (op *redirOp) invoke(fm *Frame) error { var dst int if op.dstOp.body == nil { @@ -509,10 +513,13 @@ func (op *redirOp) invoke(fm *Frame) error { if err != nil { return err } - if src == -1 { + switch { + case src == -1: // close fm.ports[dst] = &Port{} - } else { + case src >= len(fm.ports) || fm.ports[src] == nil: + return invalidFD{src} + default: fm.ports[dst] = fm.ports[src].Fork() } } else { diff --git a/pkg/eval/compile_effect_test.go b/pkg/eval/compile_effect_test.go index 60eb08bc..1297d216 100644 --- a/pkg/eval/compile_effect_test.go +++ b/pkg/eval/compile_effect_test.go @@ -1,8 +1,15 @@ package eval -import "testing" +import ( + "testing" + + "github.com/elves/elvish/pkg/util" +) func TestCompileEffect(t *testing.T) { + _, cleanup := util.InTestDir() + defer cleanup() + Test(t, // Chunks // ------ @@ -67,21 +74,26 @@ func TestCompileEffect(t *testing.T) { // Redirections // ------------ - That("f=(mktemp elvXXXXXX); echo 233 > $f; cat < $f; rm $f"). - Prints("233\n"), - + That("echo 233 > out1", " slurp < out1"). + Puts("233\n"), // Redirections from special form. - That(`f = (mktemp elvXXXXXX)`, - `for x [lorem ipsum] { echo $x } > $f`, - `cat $f`, - `rm $f`).Prints("lorem\nipsum\n"), - + That(`for x [lorem ipsum] { echo $x } > out2`, `slurp < out2`). + Puts("lorem\nipsum\n"), + // Using numeric FDs as source and destination. + That(`{ echo foobar >&2 } 2> out3`, `slurp < out3`). + Puts("foobar\n"), + // Using named FDs as source and destination. + That(`{ echo foobar >&stderr } stderr> out4`, `slurp < out4`). + Puts("foobar\n"), + // Using a new FD as source throws an exception. + That(`echo foo >&4`).ThrowsAny(), + // Using a new FD as destination is OK, and makes it available. + That(`{ echo foo >&4 } 4>out5`, `slurp < out5`).Puts("foo\n"), // Redirections from File object. - That(`fname=(mktemp elvXXXXXX); echo haha > $fname; - f=(fopen $fname); cat <$f; fclose $f; rm $fname`).Prints("haha\n"), - + That(`echo haha > out3`, `f = (fopen out3)`, `slurp <$f`, ` fclose $f`). + Puts("haha\n"), // Redirections from Pipe object. - That(`p=(pipe); echo haha > $p; pwclose $p; cat < $p; prclose $p`). - Prints("haha\n"), + That(`p = (pipe); echo haha > $p; pwclose $p; slurp < $p; prclose $p`). + Puts("haha\n"), ) } diff --git a/pkg/eval/frame.go b/pkg/eval/frame.go index d4d93d7e..6eef8787 100644 --- a/pkg/eval/frame.go +++ b/pkg/eval/frame.go @@ -121,7 +121,9 @@ func linesToChan(r io.Reader, ch chan<- interface{}) { func (fm *Frame) fork(name string) *Frame { newPorts := make([]*Port, len(fm.ports)) for i, p := range fm.ports { - newPorts[i] = p.Fork() + if p != nil { + newPorts[i] = p.Fork() + } } return &Frame{ fm.Evaler, fm.srcMeta,