@@ -5577,6 +5577,27 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
55775577#endif
55785578
55795579#if WASM_ENABLE_BRANCH_HINTS != 0
5580+ /**
5581+ * Count the number of branch instructions for the specified function.
5582+ */
5583+ static uint32
5584+ calculate_num_branch_instructions(const WASMFunction *func)
5585+ {
5586+ const uint8 *code = func->code;
5587+ const uint8 *code_end = code + func->code_size;
5588+ uint32 max_hints = 0;
5589+
5590+ while (code < code_end) {
5591+ uint8 opcode = *code++;
5592+
5593+ if (opcode == WASM_OP_IF || opcode == WASM_OP_BR_IF) {
5594+ max_hints++;
5595+ }
5596+ }
5597+
5598+ return max_hints;
5599+ }
5600+
55805601static bool
55815602handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
55825603 WASMModule *module, char *error_buf,
@@ -5611,22 +5632,52 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
56115632
56125633 uint32 num_hints;
56135634 read_leb_uint32(buf, buf_end, num_hints);
5635+
5636+ /* Ensure that num_hints doesn't exceed the actual number of branch
5637+ * instructions */
5638+ WASMFunction *func =
5639+ module->functions[func_idx - module->import_function_count];
5640+ uint32 max_branch_instructions =
5641+ calculate_num_branch_instructions(func);
5642+ if (num_hints > max_branch_instructions) {
5643+ set_error_buf_v(
5644+ error_buf, error_buf_size,
5645+ "invalid number of branch hints: expected at most %u, got %u",
5646+ max_branch_instructions, num_hints);
5647+ goto fail;
5648+ }
5649+
56145650 struct WASMCompilationHintBranchHint *new_hints = loader_malloc(
56155651 sizeof(struct WASMCompilationHintBranchHint) * num_hints, error_buf,
56165652 error_buf_size);
5653+ if (!new_hints) {
5654+ goto fail;
5655+ }
56175656 for (uint32 j = 0; j < num_hints; ++j) {
56185657 struct WASMCompilationHintBranchHint *new_hint = &new_hints[j];
56195658 new_hint->next = NULL;
56205659 new_hint->type = WASM_COMPILATION_BRANCH_HINT;
56215660 read_leb_uint32(buf, buf_end, new_hint->offset);
56225661
5662+ /* Validate offset is within the function's code bounds */
5663+ if (new_hint->offset >= func->code_size) {
5664+ set_error_buf_v(
5665+ error_buf, error_buf_size,
5666+ "invalid branch hint offset: %u exceeds function "
5667+ "code size %u",
5668+ new_hint->offset, func->code_size);
5669+ goto fail;
5670+ }
5671+
56235672 uint32 size;
56245673 read_leb_uint32(buf, buf_end, size);
56255674 if (size != 1) {
56265675 set_error_buf_v(error_buf, error_buf_size,
56275676 "invalid branch hint size, expected 1, got %d.",
56285677 size);
5629- wasm_runtime_free(new_hint);
5678+ /* Do not free new_hints here - any hints already linked into
5679+ * the module structure will be freed during module cleanup.
5680+ * Freeing here would cause a double-free. */
56305681 goto fail;
56315682 }
56325683
@@ -5639,7 +5690,9 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
56395690 set_error_buf_v(error_buf, error_buf_size,
56405691 "invalid branch hint, expected 0 or 1, got %d",
56415692 data);
5642- wasm_runtime_free(new_hint);
5693+ /* Do not free new_hints here - any hints already linked into
5694+ * the module structure will be freed during module cleanup.
5695+ * Freeing here would cause a double-free. */
56435696 goto fail;
56445697 }
56455698
@@ -5720,7 +5773,7 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
57205773#else
57215774 if (name_len == 25
57225775 && memcmp((const char *)p, "metadata.code.branch_hint", 25) == 0) {
5723- LOG_VERBOSE ("Found branch hint section, but branch hints are disabled "
5776+ LOG_WARNING ("Found branch hint section, but branch hints are disabled "
57245777 "in this build, skipping.");
57255778 }
57265779#endif
0 commit comments