[PATCH] libtracecmd: Fix rb-tree deletion
Steven Rostedt <[email protected]> Fri, 24 Apr 2026 15:32:17 -0400
| Newsgroups | org.kernel.vger.linux-trace-devel |
|---|---|
| Message-ID | <[email protected]> |
From: "Steven Rostedt (Google)" <[email protected]> The trace_rbtree_delete() does a fix up call if the y node is BLACK. It calls the fixup code on the y node's left or right child. But if the y node doesn't have any children, it crashes with a NULL pointer dereference. Use a "nil" node for the x child if it y had no children. This makes the fixup code work properly. Link: https://bugzilla.kernel.org/show_bug.cgi?id=221171 Reported-by: Jann Horn <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]> --- lib/trace-cmd/trace-rbtree.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/trace-cmd/trace-rbtree.c b/lib/trace-cmd/trace-rbtree.c index a541399a1b4d..523881699440 100644 --- a/lib/trace-cmd/trace-rbtree.c +++ b/lib/trace-cmd/trace-rbtree.c @@ -26,6 +26,11 @@ static bool is_left(struct trace_rbtree_node *node) return node == node->parent->left; } +static bool is_black(struct trace_rbtree_node *node) +{ + return !node || node->color == BLACK; +} + static struct trace_rbtree_node **get_parent_ptr(struct trace_rbtree *tree, struct trace_rbtree_node *node) { @@ -261,12 +266,12 @@ static void tree_fixup(struct trace_rbtree *tree, struct trace_rbtree_node *node rotate_left(tree, node->parent); old_right = node->parent->right; } - if (old_right->left->color == BLACK && - old_right->right->color == BLACK) { + if (is_black(old_right->left) && + is_black(old_right->right)) { old_right->color = RED; node = node->parent; } else { - if (old_right->right->color == BLACK) { + if (is_black(old_right->right)) { old_right->left->color = BLACK; old_right->color = RED; rotate_right(tree, old_right); @@ -287,12 +292,12 @@ static void tree_fixup(struct trace_rbtree *tree, struct trace_rbtree_node *node rotate_right(tree, node->parent); old_left = node->parent->left; } - if (old_left->right->color == BLACK && - old_left->left->color == BLACK) { + if (is_black(old_left->right) && + is_black(old_left->left)) { old_left->color = RED; node = node->parent; } else { - if (old_left->left->color == BLACK) { + if (is_black(old_left->left)) { old_left->right->color = BLACK; old_left->color = RED; rotate_left(tree, old_left); @@ -312,6 +317,7 @@ static void tree_fixup(struct trace_rbtree *tree, struct trace_rbtree_node *node void trace_rbtree_delete(struct trace_rbtree *tree, struct trace_rbtree_node *node) { struct trace_rbtree_node *x, *y; + struct trace_rbtree_node nil; bool do_fixup = false; if (!node->left && !node->right && !node->parent) { @@ -329,8 +335,14 @@ void trace_rbtree_delete(struct trace_rbtree *tree, struct trace_rbtree_node *no else x = y->right; - if (x) - x->parent = y->parent; + if (!x) { + x = &nil; + x->color = BLACK; + x->left = NULL; + x->right = NULL; + } + + x->parent = y->parent; if (!y->parent) { tree->node = x; @@ -365,6 +377,12 @@ void trace_rbtree_delete(struct trace_rbtree *tree, struct trace_rbtree_node *no if (do_fixup) tree_fixup(tree, x); + if (x == &nil) { + if (is_left(x)) + x->parent->left = NULL; + else + x->parent->right = NULL; + } out: node->parent = node->left = node->right = NULL; tree->nr_nodes--; -- 2.53.0