aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/runtime
diff options
context:
space:
mode:
authorJaden Weiss <[email protected]>2020-04-12 19:08:44 -0400
committerRon Evans <[email protected]>2020-04-13 08:28:24 +0200
commit9c78f7039debcbadf3968d902e144ac8953a5dd6 (patch)
tree774a37de98c1d53a1b38e8200d299f3a050a1b87 /src/runtime
parent9890c760cf9b6c2dd7cc6959a46caf0f9826f72b (diff)
downloadtinygo-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.go15
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(),