Description
When the prefixed output mode is enabled, Task can panic while a command writes to stdout and stderr concurrently.
I observed the following panic with Task v3.43.3:
panic: runtime error: slice bounds out of range [2687:2453]
goroutine 178 [running]:
bytes.(*Buffer).readSlice(...)
bytes/buffer.go:440
bytes.(*Buffer).ReadString(...)
bytes/buffer.go:459
github.com/go-task/task/v3/internal/output.(*prefixWriter).writeOutputLines(0xc0001bab90, 0x0)
github.com/go-task/task/v3@v3.43.3/internal/output/prefixed.go:58 +0x3a
github.com/go-task/task/v3/internal/output.(*prefixWriter).Write(...)
github.com/go-task/task/v3@v3.43.3/internal/output/prefixed.go:49 +0x45
io.copyBuffer(...)
io/io.go:431
os/exec.(*Cmd).writerDescriptor.func1()
os/exec/exec.go:580
A second goroutine panicked at the same time with the same prefixWriter address.
Prefixed.WrapWriter returns one prefixWriter instance for both stdout and stderr:
pw := &prefixWriter{writer: stdOut, prefix: prefix, prefixed: p}
return pw, pw, func(error) error { return pw.close() }
os/exec copies stdout and stderr in separate goroutines, so both goroutines may call prefixWriter.Write concurrently. Write and writeOutputLines access pw.buff (bytes.Buffer) without synchronization. bytes.Buffer is not safe for concurrent use.
PR #1974 protects the shared prefix map and counter, but it does not protect each prefixWriter's buffer.
Expected behavior: concurrent stdout/stderr output should be prefixed without a data race or panic.
Version
v3.43.3. The relevant prefixWriter implementation appears unchanged on the current main branch and in v3.52.0.
Operating system
Linux 5.15.167.4-microsoft-standard-WSL2 x86_64 GNU/Linux
Experiments Enabled
None.
Example Taskfile
version: "3"
output: prefixed
tasks:
default:
cmds:
- |
for i in $(seq 1 10000); do
echo "stdout line ${i}" &
echo "stderr line ${i}" >&2 &
done
wait
Because this is a race, multiple runs or go test -race around prefixWriter may be needed for a deterministic signal.
Description
When the
prefixedoutput mode is enabled, Task can panic while a command writes to stdout and stderr concurrently.I observed the following panic with Task v3.43.3:
A second goroutine panicked at the same time with the same
prefixWriteraddress.Prefixed.WrapWriterreturns oneprefixWriterinstance for both stdout and stderr:os/execcopies stdout and stderr in separate goroutines, so both goroutines may callprefixWriter.Writeconcurrently.WriteandwriteOutputLinesaccesspw.buff(bytes.Buffer) without synchronization.bytes.Bufferis not safe for concurrent use.PR #1974 protects the shared prefix map and counter, but it does not protect each
prefixWriter's buffer.Expected behavior: concurrent stdout/stderr output should be prefixed without a data race or panic.
Version
v3.43.3. The relevant
prefixWriterimplementation appears unchanged on the currentmainbranch and in v3.52.0.Operating system
Linux 5.15.167.4-microsoft-standard-WSL2 x86_64 GNU/Linux
Experiments Enabled
None.
Example Taskfile
Because this is a race, multiple runs or
go test -racearoundprefixWritermay be needed for a deterministic signal.