Skip to content

vim25/progress: fix 'send on closed channel' panic on early upload failure - #4145

Open
bhagatp10 wants to merge 1 commit into
vmware:mainfrom
bhagatp10:fix_panic_in_vmdk_upload_issue
Open

bhagatp10 wants to merge 1 commit into
vmware:mainfrom
bhagatp10:fix_panic_in_vmdk_upload_issue

Conversation

@bhagatp10

Copy link
Copy Markdown

Description

soap.Client.Upload wraps the request body in a progress.reader and defers pr.Done(err), which closes the progress channel. If the server replies before it has read the whole body (for example vCenter returning 503 mid-VMDK upload), http.Client.Do returns and Done closes the channel. net/http's writer goroutine may still be reading the body at that point. It calls reader.Read, which sends a report on the closed channel and panics with send on closed channel.

Fix:
In vim25/progress/reader.go:

  • Add a sync.Mutex and a done flag to reader. Read and Done hold the lock around the channel send and close.
  • After Done, Read still returns data and errors from the underlying reader, but sends no more progress reports.
  • Done is idempotent, so a second call can't double-close the channel.
  • pos is now guarded by the same mutex. This also removes a data race between Read (transport goroutine) and Done (caller goroutine).
  • The underlying Read runs outside the lock, so a slow source never blocks Done.

Closes: #3831

How Has This Been Tested?

  • Added new tests TestReaderReadAfterDone, TestReaderConcurrentReadDone, TestReaderReadError and TestUploadEarlyErrorResponse to cover different scenarios.
  • Ran go test -race -count=5 ./vim25/progress ./vim25/soap and go test -race ./vim25/... ./object ./nfc to run these tests.

…ilure

soap.Client.Upload wraps the request body in a progress.reader and defers pr.Done(err), which closes the progress channel. If the server replies before it has read the whole body (for example vCenter returning 503 mid-VMDK upload), http.Client.Do returns and Done closes the channel. net/http's writer goroutine may still be reading the body at that point. It calls reader.Read, which sends a report on the closed channel and panics with send on closed channel.

Fix:
In vim25/progress/reader.go:

- Add a sync.Mutex and a done flag to reader. Read and Done hold the lock around the channel send and close.
- After Done, Read still returns data and errors from the underlying reader, but sends no more progress reports.
- Done is idempotent, so a second call can't double-close the channel.
- pos is now guarded by the same mutex. This also removes a data race between Read (transport goroutine) and Done (caller goroutine).
- The underlying Read runs outside the lock, so a slow source never blocks Done.

Signed-off-by: Prajwal Bhagat <prajwal.bhagat@broadcom.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

panics in case of issues during vmdk upload

1 participant