From 46130bc721655f8c3cab2d88191cf2e344acfd4e Mon Sep 17 00:00:00 2001 From: Mel Henning Date: Mon, 5 Jan 2026 12:47:36 -0500 Subject: [PATCH] util/rmq: Fix uninitialized read in preprocess We were previously always reading table->width elements from the previous row in this loop, but we write fewer entries than that to the current row. Fix this by adjusting the element count. Fixes: 0d07b860733 ("util: Add range_minimum_query") Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/14593 Acked-by: Alyssa Rosenzweig (cherry picked from commit 417116122771e9d0413d8f8d50317076bcdbb271) Part-of: --- .pick_status.json | 2 +- src/util/range_minimum_query.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index b4b4de4608d..946f17a5505 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -794,7 +794,7 @@ "description": "util/rmq: Fix uninitialized read in preprocess", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "0d07b86073342820196e00213f240158481f3b4a", "notes": null diff --git a/src/util/range_minimum_query.c b/src/util/range_minimum_query.c index 0be55fc70f4..75277bd6f6c 100644 --- a/src/util/range_minimum_query.c +++ b/src/util/range_minimum_query.c @@ -35,6 +35,13 @@ elementwise_minimum(uint32_t *restrict out, } } +/** + * For a given level (row) of the table, how many input values is the + * minimum computed over? + * + * Each row of the table has (table->width - rmq_distance(level) + 1) + * valid elements. + */ static uint32_t rmq_distance(int32_t level) { @@ -46,10 +53,18 @@ range_minimum_query_table_preprocess(struct range_minimum_query_table *table) { for (uint32_t i = 1; i < table->height; i++) { uint32_t in_distance = rmq_distance(i - 1); + uint32_t out_distance = rmq_distance(i); uint32_t *in_row = table->table + table->width * (i - 1); uint32_t *out_row = table->table + table->width * i; + /* + * This reads elements [0, x) from in_row, where x is: + * in_distance + table->width - out_distance + 1 + * in_distance + table->width - (2 * in_distance) + 1 + * table->width - in_distance + 1 + * which is the number of valid elements in in_row + */ elementwise_minimum(out_row, in_row, in_row + in_distance, - table->width - in_distance); + table->width - out_distance + 1); } } @@ -58,6 +73,7 @@ range_minimum_query(struct range_minimum_query_table *const table, uint32_t left_idx, uint32_t right_idx) { assert(left_idx < right_idx); + assert(right_idx <= table->width); const uint32_t distance = right_idx - left_idx; uint32_t level = util_logbase2(distance); @@ -65,6 +81,15 @@ range_minimum_query(struct range_minimum_query_table *const table, assert(distance < 2 * rmq_distance(level)); assert(level < table->height); + /* + * Since right_idx <= table->width by precondition, we know + * right_idx - rmq_distance(level) <= table->width - rmq_distance(level) + * right_idx - rmq_distance(level) < table->width - rmq_distance(level) + 1 + * which means that the read for `right` is in bounds. + * + * The read for `left` is then in bounds because + * left_idx == right_idx - width <= right_idx - rmq_distance(level) + */ uint32_t *const row = table->table + table->width * level; uint32_t left = row[left_idx]; uint32_t right = row[right_idx - rmq_distance(level)];