!124 [sync] PR-123: Fixed goroutine abnormal when accessiong pollDesc r/w Gs inconsistently
From: @openeuler-sync-bot Reviewed-by: @jing-rui Signed-off-by: @jing-rui
This commit is contained in:
commit
ea4568a9c9
177
0077-release-branch.go1.16-runtime-consistently-access-po.patch
Normal file
177
0077-release-branch.go1.16-runtime-consistently-access-po.patch
Normal file
@ -0,0 +1,177 @@
|
||||
From 55d5b4cd27af9070cbbbef4449dc56d528cdd9aa Mon Sep 17 00:00:00 2001
|
||||
From: Michael Pratt <mpratt@google.com>
|
||||
Date: Thu, 14 Oct 2021 18:18:49 -0400
|
||||
Subject: [PATCH] [release-branch.go1.16] runtime: consistently access pollDesc
|
||||
r/w Gs with atomics
|
||||
|
||||
Both netpollblock and netpollunblock read gpp using a non-atomic load.
|
||||
When consuming a ready event, netpollblock clears gpp using a non-atomic
|
||||
store, thus skipping a barrier.
|
||||
|
||||
Thus on systems with weak memory ordering, a sequence like so this is
|
||||
possible:
|
||||
|
||||
T1 T2
|
||||
|
||||
1. netpollblock: read gpp -> pdReady
|
||||
2. netpollblock: store gpp -> 0
|
||||
|
||||
3. netpollunblock: read gpp -> pdReady
|
||||
4. netpollunblock: return
|
||||
|
||||
i.e., without a happens-before edge between (2) and (3), netpollunblock
|
||||
may read the stale value of gpp.
|
||||
|
||||
Switch these access to use atomic loads and stores in order to create
|
||||
these edges.
|
||||
|
||||
For ease of future maintainance, I've simply changed rg and wg to always
|
||||
be accessed atomically, though I don't believe pollOpen or pollClose
|
||||
require atomics today.
|
||||
|
||||
For #48925
|
||||
Fixes #49009
|
||||
|
||||
Change-Id: I903ea667eea320277610b4f969129935731520c3
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/355952
|
||||
Trust: Michael Pratt <mpratt@google.com>
|
||||
Run-TryBot: Michael Pratt <mpratt@google.com>
|
||||
TryBot-Result: Go Bot <gobot@golang.org>
|
||||
Reviewed-by: Michael Knyszek <mknyszek@google.com>
|
||||
Reviewed-by: David Chase <drchase@google.com>
|
||||
(cherry picked from commit 1b072b3ed56c18619587354f499fcda5279718a2)
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/356370
|
||||
|
||||
Reference:https://go-review.googlesource.com/c/go/+/356370
|
||||
Conflict:NA
|
||||
---
|
||||
src/runtime/netpoll.go | 43 +++++++++++++++++++++++++-----------------
|
||||
1 file changed, 26 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
|
||||
index 77eb3aa4c6..f296b0a4db 100644
|
||||
--- a/src/runtime/netpoll.go
|
||||
+++ b/src/runtime/netpoll.go
|
||||
@@ -74,6 +74,7 @@ type pollDesc struct {
|
||||
// pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification)
|
||||
// proceed w/o taking the lock. So closing, everr, rg, rd, wg and wd are manipulated
|
||||
// in a lock-free way by all operations.
|
||||
+ // TODO(golang.org/issue/49008): audit these lock-free fields for continued correctness.
|
||||
// NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
|
||||
// that will blow up when GC starts moving objects.
|
||||
lock mutex // protects the following fields
|
||||
@@ -82,11 +83,11 @@ type pollDesc struct {
|
||||
everr bool // marks event scanning error happened
|
||||
user uint32 // user settable cookie
|
||||
rseq uintptr // protects from stale read timers
|
||||
- rg uintptr // pdReady, pdWait, G waiting for read or nil
|
||||
+ rg uintptr // pdReady, pdWait, G waiting for read or nil. Accessed atomically.
|
||||
rt timer // read deadline timer (set if rt.f != nil)
|
||||
rd int64 // read deadline
|
||||
wseq uintptr // protects from stale write timers
|
||||
- wg uintptr // pdReady, pdWait, G waiting for write or nil
|
||||
+ wg uintptr // pdReady, pdWait, G waiting for write or nil. Accessed atomically.
|
||||
wt timer // write deadline timer
|
||||
wd int64 // write deadline
|
||||
self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
|
||||
@@ -143,20 +144,22 @@ func poll_runtime_isPollServerDescriptor(fd uintptr) bool {
|
||||
func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
|
||||
pd := pollcache.alloc()
|
||||
lock(&pd.lock)
|
||||
- if pd.wg != 0 && pd.wg != pdReady {
|
||||
+ wg := atomic.Loaduintptr(&pd.wg)
|
||||
+ if wg != 0 && wg != pdReady {
|
||||
throw("runtime: blocked write on free polldesc")
|
||||
}
|
||||
- if pd.rg != 0 && pd.rg != pdReady {
|
||||
+ rg := atomic.Loaduintptr(&pd.rg)
|
||||
+ if rg != 0 && rg != pdReady {
|
||||
throw("runtime: blocked read on free polldesc")
|
||||
}
|
||||
pd.fd = fd
|
||||
pd.closing = false
|
||||
pd.everr = false
|
||||
pd.rseq++
|
||||
- pd.rg = 0
|
||||
+ atomic.Storeuintptr(&pd.rg, 0)
|
||||
pd.rd = 0
|
||||
pd.wseq++
|
||||
- pd.wg = 0
|
||||
+ atomic.Storeuintptr(&pd.wg, 0)
|
||||
pd.wd = 0
|
||||
pd.self = pd
|
||||
unlock(&pd.lock)
|
||||
@@ -171,10 +174,12 @@ func poll_runtime_pollClose(pd *pollDesc) {
|
||||
if !pd.closing {
|
||||
throw("runtime: close polldesc w/o unblock")
|
||||
}
|
||||
- if pd.wg != 0 && pd.wg != pdReady {
|
||||
+ wg := atomic.Loaduintptr(&pd.wg)
|
||||
+ if wg != 0 && wg != pdReady {
|
||||
throw("runtime: blocked write on closing polldesc")
|
||||
}
|
||||
- if pd.rg != 0 && pd.rg != pdReady {
|
||||
+ rg := atomic.Loaduintptr(&pd.rg)
|
||||
+ if rg != 0 && rg != pdReady {
|
||||
throw("runtime: blocked read on closing polldesc")
|
||||
}
|
||||
netpollclose(pd.fd)
|
||||
@@ -198,9 +203,9 @@ func poll_runtime_pollReset(pd *pollDesc, mode int) int {
|
||||
return errcode
|
||||
}
|
||||
if mode == 'r' {
|
||||
- pd.rg = 0
|
||||
+ atomic.Storeuintptr(&pd.rg, 0)
|
||||
} else if mode == 'w' {
|
||||
- pd.wg = 0
|
||||
+ atomic.Storeuintptr(&pd.wg, 0)
|
||||
}
|
||||
return pollNoError
|
||||
}
|
||||
@@ -410,6 +415,8 @@ func netpollgoready(gp *g, traceskip int) {
|
||||
|
||||
// returns true if IO is ready, or false if timedout or closed
|
||||
// waitio - wait only for completed IO, ignore errors
|
||||
+// Concurrent calls to netpollblock in the same mode are forbidden, as pollDesc
|
||||
+// can hold only a single waiting goroutine for each mode.
|
||||
func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
|
||||
gpp := &pd.rg
|
||||
if mode == 'w' {
|
||||
@@ -418,17 +425,19 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
|
||||
|
||||
// set the gpp semaphore to pdWait
|
||||
for {
|
||||
- old := *gpp
|
||||
- if old == pdReady {
|
||||
- *gpp = 0
|
||||
+ // Consume notification if already ready.
|
||||
+ if atomic.Casuintptr(gpp, pdReady, 0) {
|
||||
return true
|
||||
}
|
||||
- if old != 0 {
|
||||
- throw("runtime: double wait")
|
||||
- }
|
||||
if atomic.Casuintptr(gpp, 0, pdWait) {
|
||||
break
|
||||
}
|
||||
+
|
||||
+ // Double check that this isn't corrupt; otherwise we'd loop
|
||||
+ // forever.
|
||||
+ if v := atomic.Loaduintptr(gpp); v != pdReady && v != 0 {
|
||||
+ throw("runtime: double wait")
|
||||
+ }
|
||||
}
|
||||
|
||||
// need to recheck error states after setting gpp to pdWait
|
||||
@@ -452,7 +461,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
|
||||
}
|
||||
|
||||
for {
|
||||
- old := *gpp
|
||||
+ old := atomic.Loaduintptr(gpp)
|
||||
if old == pdReady {
|
||||
return nil
|
||||
}
|
||||
--
|
||||
2.30.2
|
||||
|
||||
10
golang.spec
10
golang.spec
@ -58,7 +58,7 @@
|
||||
|
||||
Name: golang
|
||||
Version: 1.15.7
|
||||
Release: 17
|
||||
Release: 18
|
||||
Summary: The Go Programming Language
|
||||
License: BSD and Public Domain
|
||||
URL: https://golang.org/
|
||||
@ -218,7 +218,7 @@ Patch6073: 0073-release-branch.go1.17-crypto-rand-properly-handle-la.patch
|
||||
Patch6074: 0074-release-branch.go1.17-math-big-check-buffer-lengths-.patch
|
||||
Patch6075: 0075-path-filepath-do-not-remove-prefix-.-when-following-.patch
|
||||
Patch6076: 0076-release-branch.go1.17-syscall-check-correct-group-in.patch
|
||||
|
||||
Patch6077: 0077-release-branch.go1.16-runtime-consistently-access-po.patch
|
||||
|
||||
Patch9001: 0001-drop-hard-code-cert.patch
|
||||
Patch9002: 0002-fix-patch-cmd-go-internal-modfetch-do-not-sho.patch
|
||||
@ -459,6 +459,12 @@ fi
|
||||
|
||||
%changelog
|
||||
|
||||
* Thu Spe 8 2022 hanchao<hanchao47@huawei.com> - 1.15.7-18
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC: runtime: consistently access pollDesc r/w Gs with atomics
|
||||
|
||||
* Tue Aug 30 2022 hanchao<hanchao47@huawei.com> - 1.15.7-17
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user