Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[24.0 backport] pkg/ioutils: Make subsequent Close attempts noop #47221

Merged
merged 1 commit into from Jan 25, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions pkg/ioutils/readers.go
Expand Up @@ -3,11 +3,15 @@ package ioutils // import "github.com/docker/docker/pkg/ioutils"
import (
"context"
"io"
"runtime/debug"
"sync/atomic"

// make sure crypto.SHA256, crypto.sha512 and crypto.SHA384 are registered
// TODO remove once https://github.com/opencontainers/go-digest/pull/64 is merged.
_ "crypto/sha256"
_ "crypto/sha512"

"github.com/sirupsen/logrus"
)

// ReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser
Expand All @@ -16,10 +20,15 @@ import (
type ReadCloserWrapper struct {
io.Reader
closer func() error
closed atomic.Bool
}

// Close calls back the passed closer function
func (r *ReadCloserWrapper) Close() error {
if !r.closed.CompareAndSwap(false, true) {
subsequentCloseWarn("ReadCloserWrapper")
return nil
}
return r.closer()
}

Expand Down Expand Up @@ -87,6 +96,7 @@ type cancelReadCloser struct {
cancel func()
pR *io.PipeReader // Stream to read from
pW *io.PipeWriter
closed atomic.Bool
}

// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the
Expand Down Expand Up @@ -146,6 +156,17 @@ func (p *cancelReadCloser) closeWithError(err error) {
// Close closes the wrapper its underlying reader. It will cause
// future calls to Read to return io.EOF.
func (p *cancelReadCloser) Close() error {
if !p.closed.CompareAndSwap(false, true) {
subsequentCloseWarn("cancelReadCloser")
return nil
}
p.closeWithError(io.EOF)
return nil
}

func subsequentCloseWarn(name string) {
logrus.Error("subsequent attempt to close " + name)
if logrus.GetLevel() >= logrus.DebugLevel {
logrus.Errorf("stack trace: %s", string(debug.Stack()))
}
}
10 changes: 9 additions & 1 deletion pkg/ioutils/writers.go
@@ -1,6 +1,9 @@
package ioutils // import "github.com/docker/docker/pkg/ioutils"

import "io"
import (
"io"
"sync/atomic"
)

// NopWriter represents a type which write operation is nop.
type NopWriter struct{}
Expand Down Expand Up @@ -29,9 +32,14 @@ func (f *NopFlusher) Flush() {}
type writeCloserWrapper struct {
io.Writer
closer func() error
closed atomic.Bool
}

func (r *writeCloserWrapper) Close() error {
if !r.closed.CompareAndSwap(false, true) {
subsequentCloseWarn("WriteCloserWrapper")
return nil
}
return r.closer()
}

Expand Down