mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
core/sync.try_select_raw: fix TOCTOU
Fixes a TOCTOU where the channel could be used between the call to
can_{recv,send} and {recv,send} causing an unexpected blocking
operation.
To do this we use the non-blocking try_{recv,send} and retry the check
in a loop. This guarantees non-blocking select behaviour, at the cost of
spinning if the input channels are highly contended.
Signed-off-by: Jack Mordaunt <jackmordaunt.dev@gmail.com>
This commit is contained in:
+35
-33
@@ -1189,51 +1189,53 @@ try_select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs
|
|||||||
|
|
||||||
candidate_count := builtin.len(recvs)+builtin.len(sends)
|
candidate_count := builtin.len(recvs)+builtin.len(sends)
|
||||||
candidates := ([^]Select_Op)(intrinsics.alloca(candidate_count*size_of(Select_Op), align_of(Select_Op)))
|
candidates := ([^]Select_Op)(intrinsics.alloca(candidate_count*size_of(Select_Op), align_of(Select_Op)))
|
||||||
count := 0
|
|
||||||
|
|
||||||
for c, i in recvs {
|
for {
|
||||||
if can_recv(c) {
|
count := 0
|
||||||
candidates[count] = {
|
|
||||||
is_recv = true,
|
for c, i in recvs {
|
||||||
idx = i,
|
if can_recv(c) {
|
||||||
|
candidates[count] = {
|
||||||
|
is_recv = true,
|
||||||
|
idx = i,
|
||||||
|
}
|
||||||
|
count += 1
|
||||||
}
|
}
|
||||||
count += 1
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for c, i in sends {
|
for c, i in sends {
|
||||||
if can_send(c) {
|
if can_send(c) {
|
||||||
candidates[count] = {
|
candidates[count] = {
|
||||||
is_recv = false,
|
is_recv = false,
|
||||||
idx = i,
|
idx = i,
|
||||||
|
}
|
||||||
|
count += 1
|
||||||
}
|
}
|
||||||
count += 1
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate_idx := rand.int_max(count) if count > 0 else 0
|
|
||||||
|
|
||||||
sel := candidates[candidate_idx]
|
|
||||||
if sel.is_recv {
|
|
||||||
status = .Recv
|
|
||||||
if !recv_raw(recvs[sel.idx], recv_out) {
|
|
||||||
return -1, .None
|
return -1, .None
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
status = .Send
|
|
||||||
if !send_raw(sends[sel.idx], send_msgs[sel.idx]) {
|
|
||||||
return -1, .None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sel.idx, status
|
candidate_idx := rand.int_max(count) if count > 0 else 0
|
||||||
|
|
||||||
|
sel := candidates[candidate_idx]
|
||||||
|
if sel.is_recv {
|
||||||
|
status = .Recv
|
||||||
|
if !try_recv_raw(recvs[sel.idx], recv_out) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = .Send
|
||||||
|
if !try_send_raw(sends[sel.idx], send_msgs[sel.idx]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sel.idx, status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
`Raw_Queue` is a non-thread-safe queue implementation designed to store messages
|
`Raw_Queue` is a non-thread-safe queue implementation designed to store messages
|
||||||
of fixed size and alignment.
|
of fixed size and alignment.
|
||||||
|
|||||||
Reference in New Issue
Block a user