From e8fc50ef4678c8483e1231f8578391389c704c5f Mon Sep 17 00:00:00 2001 From: Dhruv Mark Collins Date: Thu, 29 Jan 2026 08:40:52 +0000 Subject: [PATCH] freedreno,u_trace: Fix various UBSAN errors These are a handful of errors that pop up in UBSAN, a lot of them depend on compiler-specific behavior such as zero-sized VLAs being valid, while others plugged some potential bug prone code such as nullptr derefs. Signed-off-by: Dhruv Mark Collins Part-of: --- src/freedreno/fdl/fd6_layout.c | 33 ++++++++++++++---------- src/freedreno/ir3/ir3.c | 2 +- src/freedreno/ir3/ir3_compiler_nir.c | 5 ++-- src/freedreno/ir3/ir3_nir.c | 5 ++++ src/freedreno/ir3/ir3_nir_opt_preamble.c | 5 ++-- src/freedreno/ir3/ir3_ra_validate.c | 3 +++ src/freedreno/registers/gen_header.py | 2 +- src/freedreno/vulkan/tu_cmd_buffer.cc | 9 +++++-- src/freedreno/vulkan/tu_cs.cc | 1 + src/freedreno/vulkan/tu_knl_drm_msm.cc | 5 ++-- src/freedreno/vulkan/tu_pass.cc | 9 +++++++ src/freedreno/vulkan/tu_pipeline.cc | 6 ++--- src/freedreno/vulkan/tu_shader.cc | 3 ++- src/util/perf/u_trace.c | 5 ++-- 14 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/freedreno/fdl/fd6_layout.c b/src/freedreno/fdl/fd6_layout.c index f55ea19d7ea..c8f42b52f1c 100644 --- a/src/freedreno/fdl/fd6_layout.c +++ b/src/freedreno/fdl/fd6_layout.c @@ -233,20 +233,27 @@ fdl6_layout_image(struct fdl_layout *layout, const struct fd_dev_info *info, uint32_t ubwc_width0 = params->width0; uint32_t ubwc_height0 = params->height0; uint32_t ubwc_tile_height_alignment = RGB_TILE_HEIGHT_ALIGNMENT; - if (params->mip_levels > 1) { - /* With mipmapping enabled, UBWC layout is power-of-two sized, - * specified in log2 width/height in the descriptors. The height - * alignment is 64 for mipmapping, but for buffer sharing (always - * single level) other participants expect 16. - */ - ubwc_width0 = util_next_power_of_two(params->width0); - ubwc_height0 = util_next_power_of_two(params->height0); - ubwc_tile_height_alignment = 64; + if (layout->ubwc) { + if (params->mip_levels > 1) { + /* With mipmapping enabled, UBWC layout is power-of-two sized, + * specified in log2 width/height in the descriptors. The height + * alignment is 64 for mipmapping, but for buffer sharing (always + * single level) other participants expect 16. + */ + ubwc_width0 = util_next_power_of_two(params->width0); + ubwc_height0 = util_next_power_of_two(params->height0); + ubwc_tile_height_alignment = 64; + } + + layout->ubwc_width0 = align(DIV_ROUND_UP(ubwc_width0, ubwc_blockwidth), + RGB_TILE_WIDTH_ALIGNMENT); + ubwc_height0 = align(DIV_ROUND_UP(ubwc_height0, ubwc_blockheight), + ubwc_tile_height_alignment); + } else { + layout->ubwc_width0 = 0; + ubwc_height0 = 0; + layout->ubwc_layer_size = 0; } - layout->ubwc_width0 = align(DIV_ROUND_UP(ubwc_width0, ubwc_blockwidth), - RGB_TILE_WIDTH_ALIGNMENT); - ubwc_height0 = align(DIV_ROUND_UP(ubwc_height0, ubwc_blockheight), - ubwc_tile_height_alignment); uint32_t min_3d_layer_size = 0; bool in_sparse_miptail = false; diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index a374e5ad23a..73182dfadf5 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -1971,7 +1971,7 @@ ir3_valid_immediate(struct ir3_instruction *instr, int32_t immed) } /* Other than cat1 (mov) we can only encode up to 10 bits, sign-extended: */ - return !(immed & ~0x1ff) || !(-immed & ~0x1ff); + return !(immed & ~0x1ff) || !(-(uint32_t)immed & ~0x1ff); } struct ir3_instruction * diff --git a/src/freedreno/ir3/ir3_compiler_nir.c b/src/freedreno/ir3/ir3_compiler_nir.c index de20cd2155d..de4ff9ec645 100644 --- a/src/freedreno/ir3/ir3_compiler_nir.c +++ b/src/freedreno/ir3/ir3_compiler_nir.c @@ -5842,8 +5842,9 @@ ir3_compile_shader_nir(struct ir3_compiler *compiler, chsh->barrier_conflict = IR3_BARRIER_EVERYTHING; } else { assert((ctx->noutputs % 4) == 0); - unsigned outidxs[ctx->noutputs / 4]; - struct ir3_instruction *outputs[ctx->noutputs / 4]; + unsigned alloc_noutputs = ctx->noutputs == 0 ? 1 : ctx->noutputs / 4; + unsigned outidxs[alloc_noutputs]; + struct ir3_instruction *outputs[alloc_noutputs]; unsigned outputs_count = 0; struct ir3_block *b = ctx->block; diff --git a/src/freedreno/ir3/ir3_nir.c b/src/freedreno/ir3/ir3_nir.c index 842ca8653bb..22734220eb4 100644 --- a/src/freedreno/ir3/ir3_nir.c +++ b/src/freedreno/ir3/ir3_nir.c @@ -1304,6 +1304,11 @@ ir3_filter_vars_to_scratch_single_instr_limit(struct set *set, uint32_t limit, util_dynarray_append(&candidate_nonspilled, var); } + if (util_dynarray_num_elements(&candidate_nonspilled, const nir_variable *) == 0) { + util_dynarray_fini(&candidate_nonspilled); + return; + } + qsort( util_dynarray_begin(&candidate_nonspilled), util_dynarray_num_elements(&candidate_nonspilled, const nir_variable *), diff --git a/src/freedreno/ir3/ir3_nir_opt_preamble.c b/src/freedreno/ir3/ir3_nir_opt_preamble.c index 7c2b76bbf26..202285c3d55 100644 --- a/src/freedreno/ir3/ir3_nir_opt_preamble.c +++ b/src/freedreno/ir3/ir3_nir_opt_preamble.c @@ -856,8 +856,9 @@ ir3_nir_lower_preamble(nir_shader *nir, struct ir3_shader_variant *v) unsigned preamble_size = const_state->allocs.consts[IR3_CONST_ALLOC_PREAMBLE].size_vec4 * 4; - BITSET_DECLARE(promoted_to_float, preamble_size); - memset(promoted_to_float, 0, sizeof(promoted_to_float)); + /* Avoid zero-size VLA. */ + BITSET_DECLARE(promoted_to_float, preamble_size > 0 ? preamble_size : 1); + BITSET_ZERO(promoted_to_float); nir_builder builder_main = nir_builder_create(main); nir_builder *b = &builder_main; diff --git a/src/freedreno/ir3/ir3_ra_validate.c b/src/freedreno/ir3/ir3_ra_validate.c index 01bf4bae750..e7ecd11edd2 100644 --- a/src/freedreno/ir3/ir3_ra_validate.c +++ b/src/freedreno/ir3/ir3_ra_validate.c @@ -391,6 +391,9 @@ propagate_parallelcopy(struct ra_val_ctx *ctx, struct ir3_instruction *pcopy) size += reg_size(pcopy->srcs[i]); } + if (size == 0) + return; + struct reg_state srcs[size]; unsigned offset = 0; diff --git a/src/freedreno/registers/gen_header.py b/src/freedreno/registers/gen_header.py index 8c329110bb2..789edcca80b 100644 --- a/src/freedreno/registers/gen_header.py +++ b/src/freedreno/registers/gen_header.py @@ -92,7 +92,7 @@ class Field(object): val = var_name elif self.type == "fixed": type = "float" - val = "((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix) + val = "(uint32_t)((int32_t)(%s * %d.0))" % (var_name, 1 << self.radix) elif self.type == "ufixed": type = "float" val = "((uint32_t)(%s * %d.0))" % (var_name, 1 << self.radix) diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index 83da0e0411e..68afc5f4e41 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -8435,8 +8435,13 @@ tu6_draw_common(struct tu_cmd_buffer *cmd, const struct tu_shader *tcs = cmd->state.shaders[MESA_SHADER_TESS_CTRL]; /* maximum number of patches that can fit in tess factor/param buffers */ - uint32_t subdraw_size = MIN2(TU_TESS::FACTOR_SIZE / ir3_tess_factor_stride(tes->variant->key.tessellation), - TU_TESS::PARAM_SIZE / (tcs->variant->output_size * 4)); + uint32_t subdraw_size = + tcs->variant->output_size != 0 + ? MIN2( + TU_TESS::FACTOR_SIZE / + ir3_tess_factor_stride(tes->variant->key.tessellation), + TU_TESS::PARAM_SIZE / (tcs->variant->output_size * 4)) + : 0; /* convert from # of patches to draw count */ subdraw_size *= cmd->vk.dynamic_graphics_state.ts.patch_control_points; diff --git a/src/freedreno/vulkan/tu_cs.cc b/src/freedreno/vulkan/tu_cs.cc index cb3eb5fe312..af9c88cd1ad 100644 --- a/src/freedreno/vulkan/tu_cs.cc +++ b/src/freedreno/vulkan/tu_cs.cc @@ -378,6 +378,7 @@ tu_cs_alloc(struct tu_cs *cs, */ memory->map = NULL; memory->iova = 0xdead0000; + memory->writeable = false; return VK_SUCCESS; } diff --git a/src/freedreno/vulkan/tu_knl_drm_msm.cc b/src/freedreno/vulkan/tu_knl_drm_msm.cc index e3a69161105..1a47189d41d 100644 --- a/src/freedreno/vulkan/tu_knl_drm_msm.cc +++ b/src/freedreno/vulkan/tu_knl_drm_msm.cc @@ -1336,8 +1336,9 @@ msm_queue_submit(struct tu_queue *queue, void *_submit, * the memory required for page tables. Sort the entries to make sure * that neighboring mappings are next to each other. */ - qsort(submit->binds.data, nr_ops, sizeof(struct drm_msm_vm_bind_op), - compare_binds); + if (nr_ops > 1) + qsort(submit->binds.data, nr_ops, sizeof(struct drm_msm_vm_bind_op), + compare_binds); u_rwlock_rdlock(&queue->device->vm_bind_fence_lock); diff --git a/src/freedreno/vulkan/tu_pass.cc b/src/freedreno/vulkan/tu_pass.cc index 3542ec91103..ac4e696a5d4 100644 --- a/src/freedreno/vulkan/tu_pass.cc +++ b/src/freedreno/vulkan/tu_pass.cc @@ -169,6 +169,9 @@ static void tu_render_pass_add_implicit_deps(struct tu_render_pass *pass, const VkRenderPassCreateInfo2 *info) { + if (pass->attachment_count == 0) + return; + const VkAttachmentDescription2* att = info->pAttachments; bool has_external_src[info->subpassCount]; bool has_external_dst[info->subpassCount]; @@ -406,6 +409,9 @@ tu_render_pass_add_implicit_deps(struct tu_render_pass *pass, static void tu_render_pass_patch_input_gmem(struct tu_render_pass *pass) { + if (pass->attachment_count == 0) + return; + bool written[pass->attachment_count]; memset(written, 0, sizeof(written)); @@ -752,6 +758,9 @@ static void tu_render_pass_gmem_config(struct tu_render_pass *pass, const struct tu_physical_device *phys_dev) { + if (pass->attachment_count == 0) + return; + for (enum tu_gmem_layout layout = (enum tu_gmem_layout) 0; layout < TU_GMEM_LAYOUT_COUNT; layout = (enum tu_gmem_layout)(layout + 1)) { diff --git a/src/freedreno/vulkan/tu_pipeline.cc b/src/freedreno/vulkan/tu_pipeline.cc index 5c682fc8a27..4ba1894f2a2 100644 --- a/src/freedreno/vulkan/tu_pipeline.cc +++ b/src/freedreno/vulkan/tu_pipeline.cc @@ -1280,9 +1280,9 @@ tu6_emit_patch_control_points(struct tu_cs *cs, tcs->variant->tess.tcs_vertices_out); } - uint32_t patches_per_wave = - MIN2(vs_hs_local_mem_size / (patch_local_mem_size_16b * 16), - max_patches_per_wave); + uint32_t patches_per_wave = patch_local_mem_size_16b == 0 + ? 0 + : MIN2(vs_hs_local_mem_size / (patch_local_mem_size_16b * 16), max_patches_per_wave); uint32_t wave_input_size = DIV_ROUND_UP( patches_per_wave * patch_local_mem_size_16b * 16, 256); diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc index a288c884c65..edc0ce1f6fe 100644 --- a/src/freedreno/vulkan/tu_shader.cc +++ b/src/freedreno/vulkan/tu_shader.cc @@ -2702,7 +2702,8 @@ tu_shader_init(struct tu_device *dev, const void *key_data, size_t key_size) VK_SYSTEM_ALLOCATION_SCOPE_DEVICE)) return NULL; - memcpy(obj_key_data, key_data, key_size); + if (key_size > 0) + memcpy(obj_key_data, key_data, key_size); vk_pipeline_cache_object_init(&dev->vk, &shader->base, &tu_shader_ops, obj_key_data, key_size); diff --git a/src/util/perf/u_trace.c b/src/util/perf/u_trace.c index 7ee737748c8..c5c25eb67e3 100644 --- a/src/util/perf/u_trace.c +++ b/src/util/perf/u_trace.c @@ -958,8 +958,9 @@ u_trace_disable_event_range(struct u_trace_iterator begin_it, list_entry(current_chunk->node.next, struct u_trace_chunk, node); } - memset(¤t_chunk->traces[start_idx], 0, - (end_it.event_idx - start_idx) * sizeof(struct u_trace_event)); + if (current_chunk != NULL) + memset(¤t_chunk->traces[start_idx], 0, + (end_it.event_idx - start_idx) * sizeof(struct u_trace_event)); } /**