Skip to content

Commit fcec30e

Browse files
srberardlum1n0us
andauthored
Fix/branch hint parse issue (#4878)
* test,security: added example code for invalid branch hints * security: fixes parsing issue for invalid branch_hint sections * fix: improve comments and logging in branch hint handling * feat: add support for branch hints in build configuration and documentation * test: add regression tests for invalid branch hints handling ```bash $ pwd /workspaces/wasm-micro-runtime/tests/regression/ba-issues $ ./run.py -i 980002,980003 ``` --------- Signed-off-by: Stephen Berard <stephen.berard@outlook.com> Co-authored-by: liang.he@intel.com <liang.he@intel.com>
1 parent 14d84ec commit fcec30e

File tree

9 files changed

+157
-4
lines changed

9 files changed

+157
-4
lines changed

build-scripts/config_common.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,11 @@ endif ()
775775
if (WAMR_BUILD_LIME1 EQUAL 1)
776776
message (" Lime1 enabled")
777777
endif ()
778+
if (WAMR_BUILD_BRANCH_HINTS EQUAL 1)
779+
message (" Branch hints enabled")
780+
add_definitions(-DWASM_ENABLE_BRANCH_HINTS=1)
781+
endif ()
782+
778783
########################################
779784
# Show Phase4 Wasm proposals status.
780785
########################################
@@ -787,8 +792,8 @@ message (
787792
" \"Non-trapping float-to-int Conversions\"\n"
788793
" \"Sign-extension Operators\"\n"
789794
" \"WebAssembly C and C++ API\"\n"
790-
" \"Branch Hinting\"\n"
791795
" Configurable. 0 is OFF. 1 is ON:\n"
796+
" \"Branch Hinting\" via WAMR_BUILD_BRANCH_HINTS: ${WAMR_BUILD_BRANCH_HINTS}\n"
792797
" \"Bulk Memory Operation\" via WAMR_BUILD_BULK_MEMORY: ${WAMR_BUILD_BULK_MEMORY}\n"
793798
" \"Bulk-memory-opt\" via WAMR_BUILD_BULK_MEMORY_OPT: ${WAMR_BUILD_BULK_MEMORY_OPT}\n"
794799
" \"Call-indirect-overlong\" via WAMR_BUILD_CALL_INDIRECT_OVERLONG: ${WAMR_BUILD_CALL_INDIRECT_OVERLONG}\n"

core/iwasm/interpreter/wasm_loader.c

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
55805601
static bool
55815602
handle_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

doc/build_wamr.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,15 @@ SIMDE (SIMD Everywhere) implements SIMD operations in fast interpreter mode.
616616
> [!WARNING]
617617
> This is only supported in classic interpreter mode.
618618
619+
## **Branch hints**
620+
621+
- **WAMR_BUILD_BRANCH_HINTS**=1/0, default to disable if not set
622+
623+
> [!NOTE]
624+
> Enabling this feature allows the runtime to utilize branch hints for better performance during aot/jit execution.
625+
626+
## **Combination of configurations:**
627+
619628
### **Invoke general FFI**
620629
621630
- **WAMR_BUILD_INVOKE_NATIVE_GENERAL**=1/0, default to off.

doc/tiered_support.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ This tier indicates experimental features with foundational support levels. Thes
165165
| GC (Garbage Collection) | [WAMR_BUILD_GC](./build_wamr.md#garbage-collection) | Wasm Proposal |
166166
| Legacy Exception Handling | [WAMR_BUILD_EXCE_HANDLING](./build_wamr.md#exception-handling) | Wasm Proposal |
167167
| Multi-memory | [WAMR_BUILD_MULTI_MEMORY](./build_wamr.md#multi-memory) | Wasm Proposal |
168+
| Branch Hints | [WAMR_BUILD_BRANCH_HINTS](./build_wamr.md#branch-hints-feature) | Wasm Proposal |
168169
| Fast JIT | [WAMR_BUILD_FAST_JIT](./build_wamr.md#configure-fast-jit) | Running mode |
169170
| Multi-tier JIT | [Combination of flags](./build_wamr.md#configure-multi-tier-jit) | Running mode |
170171
| AoT Validator | [WAMR_BUILD_AOT_VALIDATOR](./build_wamr.md#aot-validator) | Runtime Extensions |

tests/regression/ba-issues/build_wamr.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,7 @@ build_iwasm "-DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LIBC_WASI=
6060
# build fast-jit iwasm for testing fast-jit with libc-wasi disabled
6161
build_iwasm "-DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_SIMD=0 -DWAMR_BUILD_LIBC_WASI=0" "fast-jit-wasi-disabled"
6262

63+
# build default iwasm for testing wasm loader with branch hints enabled
64+
build_iwasm "-DWAMR_BUILD_BRANCH_HINTS=1" "default-branch-hints-enabled"
65+
6366
# TODO: add more version of iwasm, for example, sgx version
Binary file not shown.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from pathlib import Path
2+
3+
def u32leb(n):
4+
out = bytearray()
5+
while True:
6+
b = n & 0x7f
7+
n >>= 7
8+
if n:
9+
b |= 0x80
10+
out.append(b)
11+
if not n:
12+
break
13+
return bytes(out)
14+
name = b"metadata.code.branch_hint"
15+
assert len(name) == 25
16+
def build_module(payload_tail, out_path):
17+
payload = b"".join([
18+
u32leb(len(name)),
19+
name,
20+
payload_tail
21+
])
22+
custom_section = b"\x00" + u32leb(len(payload)) + payload
23+
payload_type = u32leb(1) + b"\x60" + u32leb(0) + u32leb(0)
24+
sec_type = b"\x01" + u32leb(len(payload_type)) + payload_type
25+
payload_func = u32leb(1) + u32leb(0)
26+
sec_func = b"\x03" + u32leb(len(payload_func)) + payload_func
27+
body = u32leb(0) + b"\x0b"
28+
payload_code = u32leb(1) + u32leb(len(body)) + body
29+
sec_code = b"\x0a" + u32leb(len(payload_code)) + payload_code
30+
module = b"\x00asm" + b"\x01\x00\x00\x00" + sec_type + sec_func + sec_code + custom_section
31+
Path(out_path).write_bytes(module)
32+
payload_invalid_free = b"".join([
33+
b"\x01", # numFunctionHints
34+
b"\x00", # func_idx
35+
b"\x02", # num_hints
36+
b"\x00", # hint0 offset
37+
b"\x01", # hint0 size
38+
b"\x00", # hint0 data
39+
b"\x00", # hint1 offset
40+
b"\x02", # hint1 size (invalid)
41+
])
42+
build_module(payload_invalid_free, "branch_hint_invalid_free.wasm")
43+
payload_dos = b"".join([
44+
b"\x01",
45+
b"\x00",
46+
b"\xff\xff\xff\xff\x0f",
47+
])
48+
build_module(payload_dos, "branch_hint_null_deref.wasm")
Binary file not shown.

tests/regression/ba-issues/running_config.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,40 @@
18181818
"stdout content": "Exception: unsupported opcode",
18191819
"description": "classic-interp will exit gracefully when meeting simd opcodes"
18201820
}
1821+
},
1822+
{
1823+
"deprecated": false,
1824+
"ids": [
1825+
980002
1826+
],
1827+
"runtime": "iwasm-default-branch-hints-enabled",
1828+
"file": "branch_hint_invalid_free.wasm",
1829+
"mode": "fast-interp",
1830+
"options": "",
1831+
"argument": "",
1832+
"expected return": {
1833+
"ret code": 255,
1834+
"stdout content": "WASM module load failed: invalid number of branch hints: expected at most 0, got 2",
1835+
"description": ""
1836+
}
1837+
1838+
},
1839+
{
1840+
"deprecated": false,
1841+
"ids": [
1842+
980003
1843+
],
1844+
"runtime": "iwasm-default-branch-hints-enabled",
1845+
"file": "branch_hint_null_deref.wasm",
1846+
"mode": "fast-interp",
1847+
"options": "",
1848+
"argument": "",
1849+
"expected return": {
1850+
"ret code": 255,
1851+
"stdout content": "WASM module load failed: invalid number of branch hints: expected at most 0, got 42949672",
1852+
"description": ""
1853+
}
1854+
18211855
}
18221856
]
18231857
}

0 commit comments

Comments
 (0)