Skip to content

Commit 9c78f70

Browse files
niaowdeadprogram
authored andcommitted
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.
1 parent 9890c76 commit 9c78f70

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

src/runtime/chan.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,12 @@ func (b *channelBlockedList) detach() {
8585
}
8686
for i, v := range b.allSelectOps {
8787
// cancel all other channel operations that are part of this select statement
88-
if &b.allSelectOps[i] == b {
88+
switch {
89+
case &b.allSelectOps[i] == b:
90+
// This entry is the one that was already detatched.
8991
continue
90-
}
91-
if v.s.ch == nil {
92+
case v.t == nil:
93+
// This entry is not used (nil channel).
9294
continue
9395
}
9496
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
512514

513515
// construct blocked operations
514516
for i, v := range states {
517+
if v.ch == nil {
518+
// A nil channel receive will never complete.
519+
// A nil channel send would have panicked during tryChanSelect.
520+
ops[i] = channelBlockedList{}
521+
continue
522+
}
523+
515524
ops[i] = channelBlockedList{
516525
next: v.ch.blocked,
517526
t: task.Current(),

testdata/channel.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ func main() {
134134
select {
135135
case make(chan int) <- 3:
136136
println("unreachable")
137+
case <-(chan int)(nil):
138+
println("unreachable")
137139
case n := <-ch:
138140
println("select n from chan:", n)
139141
case n := <-make(chan int):

0 commit comments

Comments
 (0)