Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions builtins/tail/builtin_tail_pentest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,21 @@ func TestCmdPentestTailLinesNNegativeOne(t *testing.T) {
}

func TestCmdPentestTailLinesNMinInt64(t *testing.T) {
// -(-9223372036854775808) overflows back to itself; must be rejected cleanly.
// -(-9223372036854775808) overflows; clamped to MaxCount, so the file is printed (GNU tail behaviour).
dir := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(dir, "f.txt"), []byte("hello\n"), 0644))
_, stderr, code := tailRun(t, "tail -n -9223372036854775808 f.txt", dir)
assert.Equal(t, 1, code)
assert.Contains(t, stderr, "tail:")
stdout, _, code := tailRun(t, "tail -n -9223372036854775808 f.txt", dir)
assert.Equal(t, 0, code)
assert.Equal(t, "hello\n", stdout)
}

func TestCmdPentestTailBytesNMinInt64(t *testing.T) {
// Same overflow guard for -c.
// Same overflow clamp for -c.
dir := t.TempDir()
require.NoError(t, os.WriteFile(filepath.Join(dir, "f.txt"), []byte("hello\n"), 0644))
_, stderr, code := tailRun(t, "tail -c -9223372036854775808 f.txt", dir)
assert.Equal(t, 1, code)
assert.Contains(t, stderr, "tail:")
stdout, _, code := tailRun(t, "tail -c -9223372036854775808 f.txt", dir)
assert.Equal(t, 0, code)
assert.Equal(t, "hello\n", stdout)
}

func TestCmdPentestTailLinesNPlusZero(t *testing.T) {
Expand Down
8 changes: 5 additions & 3 deletions builtins/tail/tail.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,12 +528,14 @@ func parseCount(s string) (countMode, bool) {
return countMode{}, false
}
// GNU tail silently treats negative counts as their absolute value.
// Guard against MinInt64: -(-9223372036854775808) overflows back to itself.
// Guard against MinInt64 overflow: -(-9223372036854775808) overflows back
// to itself. Clamp to MaxCount (like any other out-of-range value) so that
// behaviour matches GNU tail, which accepts this value and prints the file.
if n < 0 {
n = -n
if n < 0 {
// Negation overflowed (was MinInt64); treat as invalid.
return countMode{}, false
// Negation overflowed (was MinInt64); clamp to MaxCount.
n = MaxCount
}
}
if n > MaxCount {
Expand Down
10 changes: 3 additions & 7 deletions interp/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"fmt"
"io"
"os"
"runtime/debug"

"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/syntax"
Expand Down Expand Up @@ -340,16 +339,13 @@ func (s ExitStatus) Error() string { return fmt.Sprintf("exit status %d", s) }
func (r *Runner) Run(ctx context.Context, node syntax.Node) (retErr error) {
defer func() {
if rec := recover(); rec != nil {
var panicOut io.Writer
if r != nil {
panicOut := io.Writer(io.Discard)
if r != nil && r.stderr != nil {
panicOut = r.stderr
}
if panicOut == nil {
panicOut = os.Stderr
}
func() {
defer func() { recover() }()
fmt.Fprintf(panicOut, "rshell: internal panic: %v\n%s\n", rec, debug.Stack())
fmt.Fprintf(panicOut, "rshell: internal panic: %v\n", rec)
}()
retErr = fmt.Errorf("internal error")
}
Expand Down
9 changes: 4 additions & 5 deletions interp/runner_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"io"
"io/fs"
"os"
"runtime/debug"
"sync"
"time"

Expand Down Expand Up @@ -140,13 +139,13 @@ func (r *Runner) cmd(ctx context.Context, cm syntax.Command) {
go func() {
defer func() {
if rec := recover(); rec != nil {
panicOut := rLeft.stderr
if panicOut == nil {
panicOut = os.Stderr
panicOut := io.Writer(io.Discard)
if rLeft.stderr != nil {
panicOut = rLeft.stderr
}
func() {
defer func() { recover() }()
fmt.Fprintf(panicOut, "rshell: internal panic: %v\n%s\n", rec, debug.Stack())
fmt.Fprintf(panicOut, "rshell: internal panic: %v\n", rec)
}()
rLeft.exit.fatal(fmt.Errorf("internal error"))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
description: tail rejects malformed offset forms like +-3 and ++5, matching GNU tail behaviour.
setup:
files:
- path: file.txt
content: "hello\n"
input:
allowed_paths: ["$DIR"]
script: |+
tail -n +-3 file.txt
expect:
stdout: ""
stderr_contains: ["tail:"]
exit_code: 1
13 changes: 13 additions & 0 deletions tests/scenarios/cmd/tail/errors/malformed_offset_plus_plus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
description: tail rejects ++N offset form as an invalid number, matching GNU tail behaviour.
setup:
files:
- path: file.txt
content: "hello\n"
input:
allowed_paths: ["$DIR"]
script: |+
tail -c ++5 file.txt
expect:
stdout: ""
stderr_contains: ["tail:"]
exit_code: 1
13 changes: 13 additions & 0 deletions tests/scenarios/cmd/tail/errors/minint64_overflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
description: tail -n -9223372036854775808 is treated as a very large count (clamped), matching GNU tail which prints the file rather than erroring.
setup:
files:
- path: file.txt
content: "hello\n"
input:
allowed_paths: ["$DIR"]
script: |+
tail -n -9223372036854775808 file.txt
expect:
stdout: "hello\n"
stderr: ""
exit_code: 0
Loading