runtime (chan): fix blocking select on a nil channel
Previously, a blocking select on a nil channel would result in a nil panic inside the channel runtime code. This change fixes the nil checks so that the select works as intended.
Этот коммит содержится в:
родитель
9890c760cf
коммит
9c78f7039d
2 изменённых файлов: 14 добавлений и 3 удалений
|
@ -85,10 +85,12 @@ func (b *channelBlockedList) detach() {
|
||||||
}
|
}
|
||||||
for i, v := range b.allSelectOps {
|
for i, v := range b.allSelectOps {
|
||||||
// cancel all other channel operations that are part of this select statement
|
// cancel all other channel operations that are part of this select statement
|
||||||
if &b.allSelectOps[i] == b {
|
switch {
|
||||||
|
case &b.allSelectOps[i] == b:
|
||||||
|
// This entry is the one that was already detatched.
|
||||||
continue
|
continue
|
||||||
}
|
case v.t == nil:
|
||||||
if v.s.ch == nil {
|
// This entry is not used (nil channel).
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
v.s.ch.blocked = v.s.ch.blocked.remove(&b.allSelectOps[i])
|
v.s.ch.blocked = v.s.ch.blocked.remove(&b.allSelectOps[i])
|
||||||
|
@ -512,6 +514,13 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelB
|
||||||
|
|
||||||
// construct blocked operations
|
// construct blocked operations
|
||||||
for i, v := range states {
|
for i, v := range states {
|
||||||
|
if v.ch == nil {
|
||||||
|
// A nil channel receive will never complete.
|
||||||
|
// A nil channel send would have panicked during tryChanSelect.
|
||||||
|
ops[i] = channelBlockedList{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ops[i] = channelBlockedList{
|
ops[i] = channelBlockedList{
|
||||||
next: v.ch.blocked,
|
next: v.ch.blocked,
|
||||||
t: task.Current(),
|
t: task.Current(),
|
||||||
|
|
2
testdata/channel.go
предоставленный
2
testdata/channel.go
предоставленный
|
@ -134,6 +134,8 @@ func main() {
|
||||||
select {
|
select {
|
||||||
case make(chan int) <- 3:
|
case make(chan int) <- 3:
|
||||||
println("unreachable")
|
println("unreachable")
|
||||||
|
case <-(chan int)(nil):
|
||||||
|
println("unreachable")
|
||||||
case n := <-ch:
|
case n := <-ch:
|
||||||
println("select n from chan:", n)
|
println("select n from chan:", n)
|
||||||
case n := <-make(chan int):
|
case n := <-make(chan int):
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче