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

os: File.Read(nil) with os.O_WRONLY behavior change in tip #19122

Closed
hirochachacha opened this issue Feb 16, 2017 · 6 comments
Closed

os: File.Read(nil) with os.O_WRONLY behavior change in tip #19122

hirochachacha opened this issue Feb 16, 2017 · 6 comments
Milestone

Comments

@hirochachacha
Copy link
Contributor

hirochachacha commented Feb 16, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version devel +0ad247c Thu Feb 16 04:35:36 2017 +0000 darwin/amd64
go version go1.8rc3 darwin/amd64
go version go1.7.3 darwin/amd64
go version go1.5.4 darwin/amd64

What operating system and processor architecture are you using (go env)?

What did you do?

If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.

package main

import (
	"fmt"
	"os"
)

func main() {
	f, err := os.OpenFile("foobar.txt", os.O_WRONLY|os.O_CREATE, 0777)
	if err != nil {
		panic(err)
	}
	_, err = f.Read(nil)

	fmt.Printf("err: %v", err)
}

What did you expect to see?

err: read foobar.txt: bad file descriptor

for all versions.

What did you see instead?

err: <nil>

for tip.

On the other hand, f.Write(nil) on os.O_RDONLY always return the error.

@ianlancetaylor
Copy link
Contributor

This is because with the recent changes to make the os package use the runtime poller, the os package has now picked up the special behavior on Read of zero bytes that was formerly restricted to the net package. That behavior is

		// If the caller wanted a zero byte read, return immediately
		// without trying (but after acquiring the readLock).
		// Otherwise syscall.Read returns 0, nil which looks like
		// io.EOF.

The comment is correct unless the descriptor is only opened for writing.

There are couple of ways we could fix this, but I think my first question is: does it really matter? What is the purpose of calling Read(nil)?

@ianlancetaylor ianlancetaylor added this to the Go1.9 milestone Feb 16, 2017
@hirochachacha
Copy link
Contributor Author

hirochachacha commented Feb 16, 2017

Thank you for your answer.
And, sorry. You are right. It doesn't happen in go1.8.

There are couple of ways we could fix this, but I think my first question is: does it really matter? What is the purpose of calling Read(nil)?

My app needs to emulate C's stdio buffer. And current implementation is something like:

type File interface {
	Write(p []byte) (nn int, err error)
	WriteString(s string) (nn int, err error)
	Read(p []byte) (n int, err error)
	ReadByte() (c byte, err error)
        ReadInt() (i int64, err error) // read next token as int64
        ReadFloat() (f float64, err error) // read next token as float64
	ReadBytes(delim byte) (line []byte, err error)
}

// roFile represents a read only file and implements File interface
type roFile struct {
   ...
}

// woFile represents a write only file and implements File interface
type woFile struct {
  ...
}

type rwFile struct {
  ...
}

Then, I need to generate the error for ReadXXX in woFile.
Currently, I am using Read(nil).
I'm Okay to make a workaround. Read([]byte{0}) ?

@hirochachacha hirochachacha changed the title os: File.Read(nil) with os.O_WRONLY behavior change since 1.8 os: File.Read(nil) with os.O_WRONLY behavior change in tip Feb 16, 2017
@ianlancetaylor
Copy link
Contributor

Read([]byte{0}) will have the side-effect of reading a single byte. I don't know if that is OK for you or not.

You could also simply record in your own data structure whether the file was opened write-only or not. That is what the standard library would have to do to change this. I think the question is whether that needs to be in the standard library or not. We've never really documented the behavior of Read(nil).

@hirochachacha
Copy link
Contributor Author

You could also simply record in your own data structure whether the file was opened write-only or not. That is what the standard library would have to do to change this.

Unfortunately, I need real system call error messages.
I've already written a workaround hirochachacha/plua@9f77670...fff4918 and it works.

I think the question is whether that needs to be in the standard library or not. We've never really documented the behavior of Read(nil).

I assume the impact is very small. But I'm not sure... Please feel free to close the issue anytime.

@ianlancetaylor
Copy link
Contributor

Closing. Can reopen if someone else has similar trouble.

@hirochachacha
Copy link
Contributor Author

Thank you for your responses!

@golang golang locked and limited conversation to collaborators Feb 17, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants