From b5c747851c82ca4b862d4f2e278565ca46d95c72 Mon Sep 17 00:00:00 2001 From: Aizal Khan Date: Sun, 27 Sep 2026 08:14:11 +0530 Subject: [PATCH 1/2] Trap on argument count mismatch in DefinedFunc::DoCall --- src/interp/interp-util.cc | 6 ++++-- src/interp/interp.cc | 10 +++++++++- src/test-interp.cc | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/interp/interp-util.cc b/src/interp/interp-util.cc index 3d21d6d099..b6b16442d8 100644 --- a/src/interp/interp-util.cc +++ b/src/interp/interp-util.cc @@ -16,6 +16,7 @@ #include "wabt/interp/interp-util.h" +#include #include #include "wabt/stream.h" @@ -84,9 +85,10 @@ void WriteValues(Stream* stream, const ValueTypes& types, const Values& values) { assert(types.size() == values.size()); - for (size_t i = 0; i < values.size(); ++i) { + size_t count = std::min(types.size(), values.size()); + for (size_t i = 0; i < count; ++i) { WriteValue(stream, TypedValue{types[i], values[i]}); - if (i != values.size() - 1) { + if (i != count - 1) { stream->Writef(", "); } } diff --git a/src/interp/interp.cc b/src/interp/interp.cc index ff869e06c7..c457b84b18 100644 --- a/src/interp/interp.cc +++ b/src/interp/interp.cc @@ -537,7 +537,15 @@ Result DefinedFunc::DoCall(Thread& thread, const Values& params, Values& results, Trap::Ptr* out_trap) { - assert(params.size() == type_.params.size()); + if (params.size() != type_.params.size()) { + *out_trap = + Trap::New(thread.store(), + StringPrintf("argument count mismatch: expected %" PRIindex + ", got %" PRIindex, + static_cast(type_.params.size()), + static_cast(params.size()))); + return Result::Error; + } thread.PushValues(type_.params, params); RunResult result = thread.PushCall(*this, out_trap); if (result == RunResult::Trap) { diff --git a/src/test-interp.cc b/src/test-interp.cc index 272676f77e..cbf2e7bbcc 100644 --- a/src/test-interp.cc +++ b/src/test-interp.cc @@ -174,6 +174,26 @@ TEST_F(InterpTest, Fac) { EXPECT_EQ(120u, results[0].Get()); } +TEST_F(InterpTest, CallArgCountMismatch) { + // (module (func (export "f") (param i32) (result i32) local.get 0)) + ReadModule({ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, + 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, + 0x66, 0x00, 0x00, 0x0a, 0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0b, + }); + Instantiate(); + auto func = GetFuncExport(0); + + // Calling with fewer arguments than the function has parameters must trap + // rather than read past the end of the params vector. + Values results; + Trap::Ptr trap; + Result result = func->Call(store_, {}, results, &trap); + + ASSERT_EQ(Result::Error, result); + ASSERT_TRUE(trap); +} + TEST_F(InterpTest, Fac_Trace) { ReadModule(s_fac_module); Instantiate(); From 15a8333525832f40a7cd62308947fd95100b7b00 Mon Sep 17 00:00:00 2001 From: Aizal Khan Date: Thu, 1 Oct 2026 14:07:45 +0530 Subject: [PATCH 2/2] Reuse the existing fac module in the arity mismatch test --- src/test-interp.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/test-interp.cc b/src/test-interp.cc index cbf2e7bbcc..92e0cc8d1a 100644 --- a/src/test-interp.cc +++ b/src/test-interp.cc @@ -175,17 +175,12 @@ TEST_F(InterpTest, Fac) { } TEST_F(InterpTest, CallArgCountMismatch) { - // (module (func (export "f") (param i32) (result i32) local.get 0)) - ReadModule({ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, - 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, - 0x66, 0x00, 0x00, 0x0a, 0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0b, - }); + ReadModule(s_fac_module); Instantiate(); auto func = GetFuncExport(0); - // Calling with fewer arguments than the function has parameters must trap - // rather than read past the end of the params vector. + // Calling the one-parameter export with no arguments must trap rather than + // read past the end of the params vector. Values results; Trap::Ptr trap; Result result = func->Call(store_, {}, results, &trap);