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

bufio: Reader.UnreadByte after Discard silently corrupts input #48446

Closed
bcmills opened this issue Sep 17, 2021 · 2 comments
Closed

bufio: Reader.UnreadByte after Discard silently corrupts input #48446

bcmills opened this issue Sep 17, 2021 · 2 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done. release-blocker
Milestone

Comments

@bcmills
Copy link
Contributor

bcmills commented Sep 17, 2021

What did you do?

On a bufio.Reader, invoke ReadByte, then Discard one or more bytes, then UnreadByte (https://play.golang.org/p/RTitxKuiikQ):

package main

import (
	"bufio"
	"strings"
	"testing"
)

func TestBytesBufferUnreadByte(t *testing.T) {
	check := func(err error) {
		if err != nil {
			t.Helper()
			t.Fatal(err)
		}
	}

	const in = "abc\n"
	t.Logf("reading %q", in)

	b := bufio.NewReader(strings.NewReader(in))

	c, err := b.ReadByte()
	check(err)
	t.Logf("read byte %q", c)

	n, err := b.Discard(1)
	check(err)
	t.Logf("discarded %v byte(s)", n)

	err = b.UnreadByte()
	t.Logf("UnreadByte: %v", err)
	var want string
	if err == nil {
		want = in[1:]
	} else {
		want = in[2:]
	}

	s, err := b.ReadString('\n')
	check(err)
	if s != want {
		t.Fatalf("buffer corrupted: read %q, expected %q", s, want)
	}
}

What did you expect to see?

UnreadByte after Discard either restores the last discarded byte, or returns a non-nil error and does not modify the buffered data.

What did you see instead?

UnreadByte overwrites the last discarded byte with the last byte returned from the last Read* call.

@bcmills
Copy link
Contributor Author

bcmills commented Sep 17, 2021

This bug also appears to affect calls to UnreadByte after WriteTo (if the underlying file has grown since WriteTo): https://play.golang.org/p/jXdZaoYPlrn

@seankhliao seankhliao added the NeedsFix The path to resolution is known, but the work has not been done. label Sep 18, 2021
@bcmills bcmills self-assigned this Sep 23, 2021
@bcmills bcmills added this to the Go1.18 milestone Sep 23, 2021
@gopherbot
Copy link

Change https://golang.org/cl/351810 mentions this issue: bufio: reject UnreadByte or UnreadRune after a Discard or WriteTo

@rsc rsc unassigned bcmills Jun 23, 2022
@golang golang locked and limited conversation to collaborators Jun 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done. release-blocker
Projects
None yet
Development

No branches or pull requests

3 participants