pkg/eval: Check FD when using it as redir source.

This fixes #788.
This commit is contained in:
Qi Xiao 2020-01-12 00:42:18 +00:00
parent c3f57432d5
commit 5550819ac0
3 changed files with 38 additions and 17 deletions

View File

@ -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 {

View File

@ -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"),
)
}

View File

@ -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,