XHTTP client: Fix a data race in WaitReadCloser (#6694)

https://github.com/XTLS/Xray-core/pull/6694#issuecomment-5575759500

---------

Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
This commit is contained in:
Eninspace
2026-09-07 22:38:16 +00:00
committed by GitHub
co-authored by 风扇滑翔翼
parent 6ce8dc53e7
commit eef6e63bc1
+17 -20
View File
@@ -68,7 +68,7 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
} }
c.transportConfig.FillStreamRequest(req, sessionId, "") c.transportConfig.FillStreamRequest(req, sessionId, "")
wrc = &WaitReadCloser{Wait: make(chan struct{})} wrc = &WaitReadCloser{wait: done.New()}
go func() { go func() {
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
@@ -188,38 +188,35 @@ func (c *DefaultDialerClient) Close() error {
} }
type WaitReadCloser struct { type WaitReadCloser struct {
Wait chan struct{} wait *done.Instance
io.ReadCloser reader atomic.Pointer[io.ReadCloser]
} }
func (w *WaitReadCloser) Set(rc io.ReadCloser) { func (w *WaitReadCloser) Set(rc io.ReadCloser) {
w.ReadCloser = rc w.reader.Store(&rc)
defer func() { if w.wait.Done() {
if recover() != nil { if p := w.reader.Swap(nil); p != nil {
rc.Close() (*p).Close()
} }
}() }
close(w.Wait) w.wait.Close()
} }
func (w *WaitReadCloser) Read(b []byte) (int, error) { func (w *WaitReadCloser) Read(b []byte) (int, error) {
if w.ReadCloser == nil { rc := w.reader.Load()
if <-w.Wait; w.ReadCloser == nil { if rc == nil {
<-w.wait.Wait()
if rc = w.reader.Load(); rc == nil {
return 0, io.ErrClosedPipe return 0, io.ErrClosedPipe
} }
} }
return w.ReadCloser.Read(b) return (*rc).Read(b)
} }
func (w *WaitReadCloser) Close() error { func (w *WaitReadCloser) Close() error {
if w.ReadCloser != nil { w.wait.Close()
return w.ReadCloser.Close() if p := w.reader.Swap(nil); p != nil {
return (*p).Close()
} }
defer func() {
if recover() != nil && w.ReadCloser != nil {
w.ReadCloser.Close()
}
}()
close(w.Wait)
return nil return nil
} }