Skip to content

fix(compiler): disable unimplemented wasm proposals in the validator and reject their opcodes - #173

Open
dmitry123 wants to merge 1 commit into
develfrom
claude/simd-validator-implementation-d4d803
Open

fix(compiler): disable unimplemented wasm proposals in the validator and reject their opcodes#173
dmitry123 wants to merge 1 commit into
develfrom
claude/simd-validator-implementation-d4d803

Conversation

@dmitry123

@dmitry123 dmitry123 commented Aug 7, 2026

Copy link
Copy Markdown
Member

Fixes FLU-1095 (CRIT-2).

Problem

CompilationConfig::wasm_features enumerated the supported proposals and filled the rest with ..Default::default(). In wasmparser-nostd 0.100.2, simd is on by default, so the validator accepted v128 instructions that the translator does not implement.

impl_visit_operator! routes every unlisted proposal to a wildcard arm that validated the operator and translated nothing. The validator's operand stack advanced; no opcode was emitted and neither stack_height nor stack_types was updated. From there drop_keep amounts and local.get/local.set depths were computed against a stack height that did not describe the emitted code.

Confirmed today as a compiler panic — a DoS on the deployment path, reachable from untrusted wasm:

thread panicked at src/compiler/translator.rs:471:
tried to keep 1 values while having only 0 values available on the frame

The latent case is worse: a shape that misses that assert yields a wrong DropKeep and wrong local depths in a module that otherwise looks valid, and per CRIT-1 the interpreter does not bounds-check those depths.

Fix

Two independent gates.

1. src/compiler/config.rs — the validator no longer accepts more than the translator implements. Every WasmFeatures field is now listed explicitly; ..Default::default() is gone. simd, relaxed_simd, threads, multi_memory, memory64, exceptions, component_model and memory_control are set to false. floats stays true (floats are translated).

Spelling out every field also makes the failure mode of a wasmparser upgrade the right one: a bump that adds a field now fails to compile instead of inheriting an unreviewed default, and a bump that flips one fails the test below.

2. src/compiler/func_builder.rs — the wildcard arm returns Err(CompilationError::NotSupportedOpcode) instead of validating-and-ignoring. Gate 1 already rejects every proposal that reaches this arm, so this is defence in depth: it is what stops the two lists drifting apart again, since today the only thing preventing a silent skip is that the validator happens to reject first.

NotSupportedOpcode is a new CompilationError variant.

On the issue's point 4 — translate_locals needed no change. It calls validator.define_locals before its own ValType::V128 => NotSupportedLocalType check, so gate 1 now rejects a v128 local first ("SIMD support is not enabled"); the existing arm stays as a guard. The operand path now mirrors it.

Tests

New tests/wasm_features.rs:

  • The CRIT-2 repro compiles to NotSupportedOpcode instead of panicking.
  • A rejection case per disabled proposal — simd (as local, parameter and global), relaxed_simd, threads, multi_memory, memory64, exceptions — each asserted against the specific validator message, so a proposal that silently becomes accepted fails CI rather than widening the language.
  • The feature set itself is pinned, including component_model and memory_control, which no core module can express in WAT. This is the test that catches a wasmparser default flip.
  • Two no-regression tests: a module combining MVP, sign-extension, saturating float-to-int, bulk memory, reference types and multi-value still compiles, and so do tail calls — confirming the stricter wildcard arm did not narrow the accepted language.

Note that relaxed-SIMD has no shape that reaches its own flag: every relaxed operator takes or returns a v128, so the SIMD gate is what rejects it. The test documents this rather than pretending otherwise.

Verification

  • cargo test — full suite green.
  • cargo test in e2e/ — 92/92 spec tests pass. The spec list contains no SIMD entries, so nothing there regressed.
  • cargo clippy --all-targets clean; cargo fmt --check clean for every file touched here.

Summary by CodeRabbit

  • Bug Fixes

    • Unsupported WebAssembly features and operators are now rejected consistently with clear errors.
    • Prevented unsupported instructions from causing compiler state inconsistencies.
    • WebAssembly feature support is now explicitly restricted, preventing unexpected behavior from dependency updates.
  • Tests

    • Added coverage for unsupported proposals, feature configuration, supported proposals, and tail calls.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9cf27de-4229-4a00-88d1-774630041b31

📥 Commits

Reviewing files that changed from the base of the PR and between b8f6091 and 6a00a37.

📒 Files selected for processing (4)
  • src/compiler/config.rs
  • src/compiler/error.rs
  • src/compiler/func_builder.rs
  • tests/wasm_features.rs

📝 Walkthrough

Walkthrough

The compiler now enumerates WebAssembly feature flags explicitly, rejects unsupported operators with CompilationError::NotSupportedOpcode, and adds tests for unsupported and supported proposals.

Changes

Wasm feature enforcement

Layer / File(s) Summary
Feature flags and compilation error contract
src/compiler/config.rs, src/compiler/error.rs
wasm_features explicitly enables supported proposals and disables unsupported proposals. CompilationError::NotSupportedOpcode and its display message are added.
Unsupported opcode rejection
src/compiler/func_builder.rs
Unsupported proposal operators now return CompilationError::NotSupportedOpcode instead of updating validator state only.
Feature enforcement regression tests
tests/wasm_features.rs
Tests cover unsupported proposals, feature flags, supported proposals, and tail calls.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: hedwig0x

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: disabling unimplemented WebAssembly proposals and rejecting unsupported opcodes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/simd-validator-implementation-d4d803

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Criterion results (vs baseline)


running 75 tests
test compiler::compiled_expr::tests::compiledexpr_eval_const_returns_none_for_global_or_funcref ... ignored
test compiler::compiled_expr::tests::compiledexpr_from_const_roundtrips ... ignored
test compiler::compiled_expr::tests::compiledexpr_funcref_and_global_introspection ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_global_get_uses_context ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i32_add_mixed_const_and_global ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i32_add_mixed_global_and_funcref ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i32_add_wraps ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i32_const ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i32_sub_wraps ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i64_const ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_i64_mul_wraps ... ignored
test compiler::compiled_expr::tests::compiledexpr_new_ref_func_uses_context ... ignored
test compiler::compiled_expr::tests::compiledexpr_zero_is_zero ... ignored
test compiler::compiled_expr::tests::constop_eval_returns_value ... ignored
test compiler::compiled_expr::tests::empty_eval_context_always_none ... ignored
test compiler::compiled_expr::tests::eval_with_context_reads_globals_and_funcs ... ignored
test compiler::compiled_expr::tests::expr_op_combines_operands_and_propagates_none ... ignored
test compiler::compiled_expr::tests::funcrefop_reads_from_context ... ignored
test compiler::compiled_expr::tests::globalop_maps_value_kinds_correctly ... ignored
test compiler::compiled_expr::tests::op_clone_panics_for_expr_variant - should panic ... ignored
test compiler::compiled_expr::tests::op_clone_works_for_non_expr_variants ... ignored
test compiler::compiled_expr::tests::op_constant_encodes_f32_f64_bits ... ignored
test compiler::compiled_expr::tests::op_constant_encodes_funcref_externref_ids ... ignored
test compiler::compiled_expr::tests::op_constant_encodes_i32_i64 ... ignored
test compiler::drop_keep::tests::test_drop_keep_translation ... ignored
test compiler::func_type_registry::tests::deduplicates_matching_signatures ... ignored
test compiler::func_type_registry::tests::index_lookup_is_stable ... ignored
test compiler::func_type_registry::tests::resolves_unique_signatures_correctly ... ignored
test compiler::parser::tests::unsupported_component_model_returns_error ... ignored
test module::tests::test_decode_exact_rejects_trailing_garbage ... ignored
test module::tests::test_decode_module_wo_source_pc ... ignored
test module::tests::test_decode_rejects_partial_source_pc ... ignored
test module::tests::test_endianness ... ignored
test module::tests::test_module_encoding ... ignored
test module::verification::tests::accepts_verified_encoded_module ... ignored
test module::verification::tests::regular_construction_does_not_verify ... ignored
test module::verification::tests::regular_decode_does_not_verify ... ignored
test module::verification::tests::rejects_branch_target_outside_code_section ... ignored
test module::verification::tests::rejects_call_target_outside_code_section ... ignored
test module::verification::tests::rejects_missing_table_index_payload ... ignored
test module::verification::tests::rejects_section_index_outside_limits ... ignored
test module::verification::tests::rejects_source_pc_outside_code_section ... ignored
test module::verification::tests::rejects_zero_local_depth ... ignored
test strategy::types::tests::checked_memory_range_end_rejects_overflow ... ignored
test types::nan_preserving_float::tests::test_neg_nan_f32 ... ignored
test types::nan_preserving_float::tests::test_neg_nan_f64 ... ignored
test types::nan_preserving_float::tests::test_ops_f32 ... ignored
test types::nan_preserving_float::tests::test_ops_f64 ... ignored
test types::opcode::tests::test_fpu_opcode_encoding_uses_offset ... ignored
test types::opcode::tests::test_opcode_code_values ... ignored
test types::opcode::tests::test_opcode_encoding ... ignored
test types::opcode::tests::test_opcode_encoding_uses_explicit_code ... ignored
test types::opcode::tests::test_opcode_size ... ignored
test types::units::tests::bytes_new16 ... ignored
test types::units::tests::bytes_new32 ... ignored
test types::units::tests::bytes_new64 ... ignored
test types::units::tests::pages_checked_add ... ignored
test types::units::tests::pages_checked_sub ... ignored
test types::units::tests::pages_max ... ignored
test types::units::tests::pages_new ... ignored
test types::units::tests::pages_to_bytes ... ignored
test types::value::copysign_regression_works ... ignored
test types::value::wasm_float_max_regression_works ... ignored
test types::value::wasm_float_min_regression_works ... ignored
test vm::store::tests::clamps_runtime_memory_limit_to_global_maximum ... ignored
test wasmtime::tests::test_call_with_charging_linear_wasmtime ... ignored
test wasmtime::tests::test_call_with_charging_param_overflow_wasmtime ... ignored
test wasmtime::tests::test_call_with_charging_quadratic_wasmtime ... ignored
test wasmtime::tests::test_wasmtime_caller_memory_read_into_vec_checks_bounds_before_allocating ... ignored
test wasmtime::tests::test_wasmtime_caller_missing_memory_returns_trap ... ignored
test wasmtime::tests::test_wasmtime_executor_memory_read_into_vec_checks_bounds_before_allocating ... ignored
test wasmtime::tests::test_wasmtime_executor_missing_entrypoint_returns_trap ... ignored
test wasmtime::tests::test_wasmtime_snapshot_missing_memory_returns_trap ... ignored
test wasmtime::types::tests::maps_unknown_wasmtime_error_to_illegal_opcode ... ignored
test wasmtime::types::tests::maps_wasmtime_traps_to_rwasm_traps ... ignored

test result: ok. 0 passed; 0 failed; 75 ignored; 0 measured; 0 filtered out; finished in 0.00s

Comparisons/bench_native
                        time:   [5.2466 ns 5.3616 ns 5.4959 ns]
Found 117 outliers among 1000 measurements (11.70%)
  41 (4.10%) high mild
  76 (7.60%) high severe
Comparisons/bench_strategy_wasmtime
                        time:   [15.888 µs 16.306 µs 16.757 µs]
Found 192 outliers among 1000 measurements (19.20%)
  48 (4.80%) high mild
  144 (14.40%) high severe
Comparisons/bench_strategy_rwasm
                        time:   [13.851 µs 14.183 µs 14.555 µs]
Found 46 outliers among 1000 measurements (4.60%)
  12 (1.20%) high mild
  34 (3.40%) high severe

Heads-up: runner perf is noisy; treat deltas as a smoke check.

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.75000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/compiler/error.rs 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants