go icon indicating copy to clipboard operation
go copied to clipboard

proposal: io: add ZeroReader io.Reader

Open tmthrgd opened this issue 2 years ago • 4 comments

Needing to read a stream of zero-bytes is an ocassional use-case of an io.Reader. io.ZeroReader would be the /dev/zero counterpoint to /dev/null and io.Discard.

One particular use-case is with cipher.StreamReader to create a CSPRNG (this is the crypto/ecdsa use below).

I've proposed it be called io.ZeroReader, but it could also be called io.Zero or similar.


Proposed API:

package io

// ZeroReader is a Reader that reads an endless stream of zero-bytes.
var ZeroReader Reader = zeroReader{}

type zeroReader struct{} 
 
func (zeroReader) Read(p []byte) (int, error) { 
	for i := range p { 
		p[i] = 0 
	} 
	return len(p), nil 
}

There are two uses of this I can find in the standard library:

https://github.com/golang/go/blob/3a7a528c2d7ee0c7b2988a7aee0b9347e973cbed/src/archive/tar/reader.go#L811-L818

https://github.com/golang/go/blob/34ab0bcc5eaf97cc0aff11cfe782e4c174d52ef0/src/crypto/ecdsa/ecdsa.go#L446-L456

...and five more in test code: here and here.

Admittedly the archive/tar use could be written differently (it seems to be just zeroing a slice), but the crypto/ecdsa use does require it.

There are also two examples in the standard library of io.ReaderAt zeroing:

https://github.com/golang/go/blob/ea14d1b6e1167159dfc8408073ef411c3cf1d7e0/src/internal/xcoff/file.go#L449-L458

https://github.com/golang/go/blob/ea14d1b6e1167159dfc8408073ef411c3cf1d7e0/src/debug/pe/file.go#L185-L194

tmthrgd avatar Dec 15 '22 02:12 tmthrgd

If you leave it as zeroing only this could make use of #56351, but you could also make it a bit more flexible by making it something like type RepeatReader struct { Value byte } or something and then make it fill the slice with Value instead of just 0.

DeedleFake avatar Dec 15 '22 05:12 DeedleFake

Duplicate of #48897

seankhliao avatar Dec 15 '22 08:12 seankhliao

Duplicate of #48897

@seankhliao I don't think this is a duplicate of #48897. That issue was seeking an io.Reader that always returns io.EOF, this issue is instead proposing an io.Reader that reads an infinite stream of zero-bytes.

Compare what this issue is requesting versus what #48897 was asking for:

var Empty Reader = emptyReader{}

type emptyReader struct {}

func (emptyReader) Read(p []byte) (n int, err error) {
    return len(p), EOF
}

Please re-open this issue.

tmthrgd avatar Dec 15 '22 10:12 tmthrgd

This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group

rsc avatar Dec 21 '22 19:12 rsc

There is a question of what type to give this thing. It is both a Reader and a ReaderAt, and we don't have an interface for that type. We would probably need to do:

var Zero ZeroReader

func (ZeroReader) Read
func (ZeroReader) ReadAt

There is also potential confusion with it being a reader that has no (zero) bytes in length, not a reader that has an infinite number of zero bytes. "A reader that returns 0 bytes" can be read either way.

There is also the question of whether this arises enough to be worthwhile. The uses in the standard library are pretty fringe. I might also worry about uses in crypto and then having to preserve some properties of the implementation that we might or might not remember to preserve.

Are the use cases really here?

rsc avatar Jan 04 '23 18:01 rsc

Note that the new clear builtin will shorten the implementation of these, making it even easier to maintain them outside the standard library.

rsc avatar Jan 11 '23 18:01 rsc

Based on the discussion above, this proposal seems like a likely decline. — rsc for the proposal review group

rsc avatar Jan 11 '23 19:01 rsc

No change in consensus, so declined. — rsc for the proposal review group

rsc avatar Jan 18 '23 19:01 rsc