Skip to content

Commit 01cd85f

Browse files
authored
Merge pull request containerd#3156 from thaJeztah/1.1_backport_issue_3118
[release/1.1 backport] runtime/v1/linux/proc/io: io race
2 parents 2bf4d3a + de85314 commit 01cd85f

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

linux/proc/io.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ import (
2424
"io"
2525
"os"
2626
"sync"
27+
"sync/atomic"
2728
"syscall"
2829

30+
"github.com/containerd/containerd/log"
2931
"github.com/containerd/fifo"
3032
runc "github.com/containerd/go-runc"
3133
)
@@ -38,7 +40,7 @@ var bufPool = sync.Pool{
3840
}
3941

4042
func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error {
41-
var sameFile io.WriteCloser
43+
var sameFile *countingWriteCloser
4244
for _, i := range []struct {
4345
name string
4446
dest func(wc io.WriteCloser, rc io.Closer)
@@ -52,7 +54,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
5254
cwg.Done()
5355
p := bufPool.Get().(*[]byte)
5456
defer bufPool.Put(p)
55-
io.CopyBuffer(wc, rio.Stdout(), *p)
57+
if _, err := io.CopyBuffer(wc, rio.Stdout(), *p); err != nil {
58+
log.G(ctx).Warn("error copying stdout")
59+
}
5660
wg.Done()
5761
wc.Close()
5862
if rc != nil {
@@ -69,7 +73,9 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
6973
cwg.Done()
7074
p := bufPool.Get().(*[]byte)
7175
defer bufPool.Put(p)
72-
io.CopyBuffer(wc, rio.Stderr(), *p)
76+
if _, err := io.CopyBuffer(wc, rio.Stderr(), *p); err != nil {
77+
log.G(ctx).Warn("error copying stderr")
78+
}
7379
wg.Done()
7480
wc.Close()
7581
if rc != nil {
@@ -96,14 +102,18 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
96102
}
97103
} else {
98104
if sameFile != nil {
105+
sameFile.count++
99106
i.dest(sameFile, nil)
100107
continue
101108
}
102109
if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil {
103110
return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err)
104111
}
105112
if stdout == stderr {
106-
sameFile = fw
113+
sameFile = &countingWriteCloser{
114+
WriteCloser: fw,
115+
count: 1,
116+
}
107117
}
108118
}
109119
i.dest(fw, fr)
@@ -129,6 +139,19 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
129139
return nil
130140
}
131141

142+
// countingWriteCloser masks io.Closer() until close has been invoked a certain number of times.
143+
type countingWriteCloser struct {
144+
io.WriteCloser
145+
count int64
146+
}
147+
148+
func (c *countingWriteCloser) Close() error {
149+
if atomic.AddInt64(&c.count, -1) > 0 {
150+
return nil
151+
}
152+
return c.WriteCloser.Close()
153+
}
154+
132155
// isFifo checks if a file is a fifo
133156
// if the file does not exist then it returns false
134157
func isFifo(path string) (bool, error) {

0 commit comments

Comments
 (0)