what happened
readWriteToCloserWrapper in pkg/ioutils/readers.go embeds io.Reader directly with no synchronization between Read and Close. When Close is called by one goroutine while another is reading (e.g. via tar-split NewInputTarStream), it results in a nil pointer dereference panic in
bufio.(*Reader).Read. This causes CRI-O crash loops during concurrent ImagePull/ImageStatus operations: cri-o/cri-o#10179
I wrote a small reproducer that triggers the exact same stack trace, it's in the CRI-O issue linked above.
Proposal
For the fix, I'm thinking we stop embedding io.Reader and instead keep it as a plain field behind a sync.Mutex. Then Read checks if the reader is nil or closed before using it, and returns a proper error instead of panicking. Same thing for the readCloserWrapper variant.
Happy to submit a fix PR.
what happened
readWriteToCloserWrapper in pkg/ioutils/readers.go embeds io.Reader directly with no synchronization between Read and Close. When Close is called by one goroutine while another is reading (e.g. via tar-split NewInputTarStream), it results in a nil pointer dereference panic in
bufio.(*Reader).Read. This causes CRI-O crash loops during concurrent ImagePull/ImageStatus operations: cri-o/cri-o#10179
I wrote a small reproducer that triggers the exact same stack trace, it's in the CRI-O issue linked above.
Proposal
For the fix, I'm thinking we stop embedding io.Reader and instead keep it as a plain field behind a sync.Mutex. Then Read checks if the reader is nil or closed before using it, and returns a proper error instead of panicking. Same thing for the readCloserWrapper variant.
Happy to submit a fix PR.