util/interval-tree: Use qatomic_read for left/right while searching

Fixes a race condition (generally without optimization) in which
the subtree is re-read after the protecting if condition.

Cc: qemu-stable@nongnu.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-07-22 20:43:45 +01:00
parent 234320cd05
commit 055b86e0f0

View File

@ -745,8 +745,9 @@ static IntervalTreeNode *interval_tree_subtree_search(IntervalTreeNode *node,
* Loop invariant: start <= node->subtree_last * Loop invariant: start <= node->subtree_last
* (Cond2 is satisfied by one of the subtree nodes) * (Cond2 is satisfied by one of the subtree nodes)
*/ */
if (node->rb.rb_left) { RBNode *tmp = qatomic_read(&node->rb.rb_left);
IntervalTreeNode *left = rb_to_itree(node->rb.rb_left); if (tmp) {
IntervalTreeNode *left = rb_to_itree(tmp);
if (start <= left->subtree_last) { if (start <= left->subtree_last) {
/* /*
@ -765,8 +766,9 @@ static IntervalTreeNode *interval_tree_subtree_search(IntervalTreeNode *node,
if (start <= node->last) { /* Cond2 */ if (start <= node->last) { /* Cond2 */
return node; /* node is leftmost match */ return node; /* node is leftmost match */
} }
if (node->rb.rb_right) { tmp = qatomic_read(&node->rb.rb_right);
node = rb_to_itree(node->rb.rb_right); if (tmp) {
node = rb_to_itree(tmp);
if (start <= node->subtree_last) { if (start <= node->subtree_last) {
continue; continue;
} }
@ -814,8 +816,9 @@ IntervalTreeNode *interval_tree_iter_first(IntervalTreeRoot *root,
IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node, IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node,
uint64_t start, uint64_t last) uint64_t start, uint64_t last)
{ {
RBNode *rb = node->rb.rb_right, *prev; RBNode *rb, *prev;
rb = qatomic_read(&node->rb.rb_right);
while (true) { while (true) {
/* /*
* Loop invariants: * Loop invariants:
@ -840,7 +843,7 @@ IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node,
} }
prev = &node->rb; prev = &node->rb;
node = rb_to_itree(rb); node = rb_to_itree(rb);
rb = node->rb.rb_right; rb = qatomic_read(&node->rb.rb_right);
} while (prev == rb); } while (prev == rb);
/* Check if the node intersects [start;last] */ /* Check if the node intersects [start;last] */