diff options
author | Jaden Weiss <[email protected]> | 2020-04-12 19:08:44 -0400 |
---|---|---|
committer | Ron Evans <[email protected]> | 2020-04-13 08:28:24 +0200 |
commit | 9c78f7039debcbadf3968d902e144ac8953a5dd6 (patch) | |
tree | 774a37de98c1d53a1b38e8200d299f3a050a1b87 /src/runtime | |
parent | 9890c760cf9b6c2dd7cc6959a46caf0f9826f72b (diff) | |
download | tinygo-9c78f7039debcbadf3968d902e144ac8953a5dd6.tar.gz tinygo-9c78f7039debcbadf3968d902e144ac8953a5dd6.zip |
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.
Diffstat (limited to 'src/runtime')
-rw-r--r-- | src/runtime/chan.go | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 95243136d..929b8c730 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -85,10 +85,12 @@ func (b *channelBlockedList) detach() { } for i, v := range b.allSelectOps { // 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 - } - if v.s.ch == nil { + case v.t == nil: + // This entry is not used (nil channel). continue } 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 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{ next: v.ch.blocked, t: task.Current(), |