Skip to content

Commit

Permalink
pkg/eval: Check FD when using it as redir source.
Browse files Browse the repository at this point in the history
This fixes #788.
  • Loading branch information
xiaq committed Jan 12, 2020
1 parent c3f5743 commit 5550819
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 17 deletions.
11 changes: 9 additions & 2 deletions pkg/eval/compile_effect.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
40 changes: 26 additions & 14 deletions 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
// ------
Expand Down Expand Up @@ -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"),
)
}
4 changes: 3 additions & 1 deletion pkg/eval/frame.go
Expand Up @@ -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,
Expand Down

0 comments on commit 5550819

Please sign in to comment.