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
io.Pipe{Reader,Writer}.Close resets error code set with CloseWithError #17992
Labels
Comments
My proposed patch looks like this: commit e781e43100151dbecdc6604d8c495ed7946e3979
Author: Aleksa Sarai <cyphar@cyphar.com>
Date: Mon Nov 21 02:23:53 2016 +1100
io: pipe: make CloseWithError final
CloseWithError would previously overwrite previously set error flags,
making a defer'd pipe.Close() set the error to EOF (clearing the
previous error flags). This was quite confusing to users, because it
meant that io.Pipes we're very different to channels (double-closing a
pipe would not produce an error and would actually affect the pipe).
Fixes: golang/go#17992
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
diff --git a/src/io/pipe.go b/src/io/pipe.go
index 7e98cd2eb788..f1379a8278f0 100644
--- a/src/io/pipe.go
+++ b/src/io/pipe.go
@@ -93,26 +93,34 @@ func (p *pipe) write(b []byte) (n int, err error) {
return
}
-func (p *pipe) rclose(err error) {
+func (p *pipe) rclose(err error) error {
if err == nil {
err = ErrClosedPipe
}
p.l.Lock()
defer p.l.Unlock()
+ if p.rerr != nil {
+ return ErrClosedPipe
+ }
p.rerr = err
p.rwait.Signal()
p.wwait.Signal()
+ return nil
}
-func (p *pipe) wclose(err error) {
+func (p *pipe) wclose(err error) error {
if err == nil {
err = EOF
}
p.l.Lock()
defer p.l.Unlock()
+ if p.werr != nil {
+ return ErrClosedPipe
+ }
p.werr = err
p.rwait.Signal()
p.wwait.Signal()
+ return nil
}
// A PipeReader is the read half of a pipe.
@@ -138,8 +146,7 @@ func (r *PipeReader) Close() error {
// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err error) error {
- r.p.rclose(err)
- return nil
+ return r.p.rclose(err)
}
// A PipeWriter is the write half of a pipe.
@@ -168,8 +175,7 @@ func (w *PipeWriter) Close() error {
//
// CloseWithError always returns nil.
func (w *PipeWriter) CloseWithError(err error) error {
- w.p.wclose(err)
- return nil
+ return w.p.wclose(err)
}
// Pipe creates a synchronous in-memory pipe.
|
cyphar
added a commit
to opencontainers/umoci
that referenced
this issue
Nov 20, 2016
It turns out that .Close() will reset the error set by .CloseWithError() which means that using defer will always cause errors to not be propagated properly. To fix this, only call .Close* once (though this is probably a Golang lib bug). Fixes: cyphar/umoci#33 Reference: golang/go#17992 Signed-off-by: Aleksa Sarai <asarai@suse.com>
cyphar
added a commit
to opencontainers/umoci
that referenced
this issue
Nov 20, 2016
It turns out that .Close() will reset the error set by .CloseWithError() which means that using defer will always cause errors to not be propagated properly. To fix this, only call .Close* once (though this is probably a Golang lib bug). Fixes: cyphar/umoci#33 Reference: golang/go#17992 Signed-off-by: Aleksa Sarai <asarai@suse.com>
Double-Close isn't really defined either way, but reading the existing docs in the io package, it looks like the existing behavior matches what the docs say, even if it wasn't what you expected. Changing it seems unwise. It seems just as likely to surprise people in the other direction and break existing code in the wild, so I'm inclined to not change behavior. |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
If you use
io.Pipe
you'll notice that calling.Close
on the writer will un-do the error code set by.CloseWithError(err)
. I'm unsure if this is a bug, but I found this to be very unexpected. In particular when it's usual for you to use adefer writer.Close()
code style. This is also available on play.golang.org: https://play.golang.org/p/zJDmmRTOLQ.If you comment out
defer writer.Close()
you see what I would expect.What did you expect to see?
What did you see instead?
In particular, I did not expect for the error returned to change to
EOF
.The text was updated successfully, but these errors were encountered: