@@ -3,11 +3,15 @@ package ioutils // import "github.com/docker/docker/pkg/ioutils"
3
3
import (
4
4
"context"
5
5
"io"
6
+ "runtime/debug"
7
+ "sync/atomic"
6
8
7
9
// make sure crypto.SHA256, crypto.sha512 and crypto.SHA384 are registered
8
10
// TODO remove once https://github.com/opencontainers/go-digest/pull/64 is merged.
9
11
_ "crypto/sha256"
10
12
_ "crypto/sha512"
13
+
14
+ "github.com/sirupsen/logrus"
11
15
)
12
16
13
17
// ReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser
@@ -16,10 +20,15 @@ import (
16
20
type ReadCloserWrapper struct {
17
21
io.Reader
18
22
closer func () error
23
+ closed atomic.Bool
19
24
}
20
25
21
26
// Close calls back the passed closer function
22
27
func (r * ReadCloserWrapper ) Close () error {
28
+ if ! r .closed .CompareAndSwap (false , true ) {
29
+ subsequentCloseWarn ("ReadCloserWrapper" )
30
+ return nil
31
+ }
23
32
return r .closer ()
24
33
}
25
34
@@ -87,6 +96,7 @@ type cancelReadCloser struct {
87
96
cancel func ()
88
97
pR * io.PipeReader // Stream to read from
89
98
pW * io.PipeWriter
99
+ closed atomic.Bool
90
100
}
91
101
92
102
// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the
@@ -146,6 +156,17 @@ func (p *cancelReadCloser) closeWithError(err error) {
146
156
// Close closes the wrapper its underlying reader. It will cause
147
157
// future calls to Read to return io.EOF.
148
158
func (p * cancelReadCloser ) Close () error {
159
+ if ! p .closed .CompareAndSwap (false , true ) {
160
+ subsequentCloseWarn ("cancelReadCloser" )
161
+ return nil
162
+ }
149
163
p .closeWithError (io .EOF )
150
164
return nil
151
165
}
166
+
167
+ func subsequentCloseWarn (name string ) {
168
+ logrus .Error ("subsequent attempt to close " + name )
169
+ if logrus .GetLevel () >= logrus .DebugLevel {
170
+ logrus .Errorf ("stack trace: %s" , string (debug .Stack ()))
171
+ }
172
+ }
0 commit comments