@@ -5567,6 +5567,27 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
55675567#endif
55685568
55695569#if WASM_ENABLE_BRANCH_HINTS != 0
5570+ /**
5571+ * Count the number of branch instructions for the specified function.
5572+ */
5573+ static uint32
5574+ calculate_num_branch_instructions(const WASMFunction *func)
5575+ {
5576+ const uint8 *code = func->code;
5577+ const uint8 *code_end = code + func->code_size;
5578+ uint32 max_hints = 0;
5579+
5580+ while (code < code_end) {
5581+ uint8 opcode = *code++;
5582+
5583+ if (opcode == WASM_OP_IF || opcode == WASM_OP_BR_IF) {
5584+ max_hints++;
5585+ }
5586+ }
5587+
5588+ return max_hints;
5589+ }
5590+
55705591static bool
55715592handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
55725593 WASMModule *module, char *error_buf,
@@ -5601,22 +5622,50 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
56015622
56025623 uint32 num_hints;
56035624 read_leb_uint32(buf, buf_end, num_hints);
5625+
5626+ /* Ensure that num_hints doesn't exceed the actual number of branch instructions */
5627+ WASMFunction *func =
5628+ module->functions[func_idx - module->import_function_count];
5629+ uint32 max_branch_instructions =
5630+ calculate_num_branch_instructions(func);
5631+ if (num_hints > max_branch_instructions) {
5632+ set_error_buf_v(
5633+ error_buf, error_buf_size,
5634+ "invalid number of branch hints: expected at most %u, got %u",
5635+ max_branch_instructions, num_hints);
5636+ goto fail;
5637+ }
5638+
56045639 struct WASMCompilationHintBranchHint *new_hints = loader_malloc(
56055640 sizeof(struct WASMCompilationHintBranchHint) * num_hints, error_buf,
56065641 error_buf_size);
5642+ if (!new_hints) {
5643+ goto fail;
5644+ }
56075645 for (uint32 j = 0; j < num_hints; ++j) {
56085646 struct WASMCompilationHintBranchHint *new_hint = &new_hints[j];
56095647 new_hint->next = NULL;
56105648 new_hint->type = WASM_COMPILATION_BRANCH_HINT;
56115649 read_leb_uint32(buf, buf_end, new_hint->offset);
56125650
5651+ /* Validate offset is within the function's code bounds */
5652+ if (new_hint->offset >= func->code_size) {
5653+ set_error_buf_v(error_buf, error_buf_size,
5654+ "invalid branch hint offset: %u exceeds function "
5655+ "code size %u",
5656+ new_hint->offset, func->code_size);
5657+ goto fail;
5658+ }
5659+
56135660 uint32 size;
56145661 read_leb_uint32(buf, buf_end, size);
56155662 if (size != 1) {
56165663 set_error_buf_v(error_buf, error_buf_size,
56175664 "invalid branch hint size, expected 1, got %d.",
56185665 size);
5619- wasm_runtime_free(new_hint);
5666+ /* Do not free new_hints here - any hints already linked into
5667+ * the module structure will be freed during module cleanup.
5668+ * Freeing here would cause a double-free. */
56205669 goto fail;
56215670 }
56225671
@@ -5629,7 +5678,9 @@ handle_branch_hint_section(const uint8 *buf, const uint8 *buf_end,
56295678 set_error_buf_v(error_buf, error_buf_size,
56305679 "invalid branch hint, expected 0 or 1, got %d",
56315680 data);
5632- wasm_runtime_free(new_hint);
5681+ /* Do not free new_hints here - any hints already linked into
5682+ * the module structure will be freed during module cleanup.
5683+ * Freeing here would cause a double-free. */
56335684 goto fail;
56345685 }
56355686
0 commit comments