Skip to content

Commit ef200b5

Browse files
gumb0axic
authored andcommitted
Add function inputs/ouput type to ImportedFunction and check in resolve
1 parent 9fc7388 commit ef200b5

3 files changed

Lines changed: 92 additions & 30 deletions

File tree

lib/fizzy/execute.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,8 +1571,27 @@ std::vector<ExternalFunction> resolve_imported_functions(
15711571
}
15721572

15731573
assert(import.desc.function_type_index < module.typesec.size());
1574-
external_functions.emplace_back(ExternalFunction{
1575-
std::move(it->function), module.typesec[import.desc.function_type_index]});
1574+
const auto& module_func_type = module.typesec[import.desc.function_type_index];
1575+
1576+
if (module_func_type.inputs != it->inputs)
1577+
{
1578+
throw instantiate_error("function " + import.module + "." + import.name +
1579+
" input types don't match imported function in module");
1580+
}
1581+
if (module_func_type.outputs.empty() && it->output.has_value())
1582+
{
1583+
throw instantiate_error("function " + import.module + "." + import.name +
1584+
" has output but is defined void in module");
1585+
}
1586+
if (!module_func_type.outputs.empty() &&
1587+
(!it->output.has_value() || module_func_type.outputs[0] != *it->output))
1588+
{
1589+
throw instantiate_error("function " + import.module + "." + import.name +
1590+
" output type doesn't match imported function in module");
1591+
}
1592+
1593+
external_functions.emplace_back(
1594+
ExternalFunction{std::move(it->function), module_func_type});
15761595
}
15771596

15781597
return external_functions;

lib/fizzy/execute.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ struct ImportedFunction
105105
{
106106
std::string module;
107107
std::string name;
108+
std::vector<ValType> inputs;
109+
std::optional<ValType> output;
108110
std::function<execution_result(Instance&, std::vector<uint64_t>, int depth)> function;
109111
};
110112

test/unittests/api_test.cpp

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ auto function_returning_value(uint64_t value) noexcept
1919
return execution_result{false, {value}};
2020
};
2121
}
22+
23+
execution_result function_returning_void(Instance&, std::vector<uint64_t>, int) noexcept
24+
{
25+
return {};
26+
}
2227
} // namespace
2328

2429
TEST(api, resolve_imported_functions)
@@ -27,19 +32,19 @@ TEST(api, resolve_imported_functions)
2732
(func (import "mod1" "foo1") (result i32))
2833
(func (import "mod1" "foo2") (param i32) (result i32))
2934
(func (import "mod2" "foo1") (param i32) (result i32))
30-
(func (import "mod2" "foo2") (param i64) (result i64))
35+
(func (import "mod2" "foo2") (param i64) (param i32))
3136
(global (import "mod1" "g") i32) ;; just to test combination with other import types
3237
*/
3338
const auto wasm = from_hex(
34-
"0061736d01000000010f036000017f60017f017f60017e017e023b05046d6f643104666f6f310000046d6f6431"
39+
"0061736d01000000010f036000017f60017f017f60027e7f00023b05046d6f643104666f6f310000046d6f6431"
3540
"04666f6f320001046d6f643204666f6f310001046d6f643204666f6f320002046d6f64310167037f00");
3641
const auto module = parse(wasm);
3742

3843
std::vector<ImportedFunction> imported_functions = {
39-
{"mod1", "foo1", function_returning_value(0)},
40-
{"mod1", "foo2", function_returning_value(1)},
41-
{"mod2", "foo1", function_returning_value(2)},
42-
{"mod2", "foo2", function_returning_value(3)},
44+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
45+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
46+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
47+
{"mod2", "foo2", {ValType::i64, ValType::i32}, std::nullopt, function_returning_void},
4348
};
4449

4550
const auto external_functions =
@@ -53,16 +58,16 @@ TEST(api, resolve_imported_functions)
5358
module, external_functions, {}, {}, std::vector<ExternalGlobal>(external_globals));
5459

5560
EXPECT_THAT(execute(*instance, 0, {}), Result(0));
56-
EXPECT_THAT(execute(*instance, 1, {}), Result(1));
57-
EXPECT_THAT(execute(*instance, 2, {}), Result(2));
58-
EXPECT_THAT(execute(*instance, 3, {}), Result(3));
61+
EXPECT_THAT(execute(*instance, 1, {0}), Result(1));
62+
EXPECT_THAT(execute(*instance, 2, {0}), Result(2));
63+
EXPECT_THAT(execute(*instance, 3, {0, 0}), Result());
5964

6065

6166
std::vector<ImportedFunction> imported_functions_reordered = {
62-
{"mod2", "foo1", function_returning_value(2)},
63-
{"mod1", "foo2", function_returning_value(1)},
64-
{"mod1", "foo1", function_returning_value(0)},
65-
{"mod2", "foo2", function_returning_value(3)},
67+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
68+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
69+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
70+
{"mod2", "foo2", {ValType::i64, ValType::i32}, std::nullopt, function_returning_void},
6671
};
6772

6873
const auto external_functions_reordered =
@@ -73,18 +78,18 @@ TEST(api, resolve_imported_functions)
7378
std::vector<ExternalGlobal>(external_globals));
7479

7580
EXPECT_THAT(execute(*instance_reordered, 0, {}), Result(0));
76-
EXPECT_THAT(execute(*instance_reordered, 1, {}), Result(1));
77-
EXPECT_THAT(execute(*instance_reordered, 2, {}), Result(2));
78-
EXPECT_THAT(execute(*instance_reordered, 3, {}), Result(3));
81+
EXPECT_THAT(execute(*instance_reordered, 1, {0}), Result(1));
82+
EXPECT_THAT(execute(*instance_reordered, 2, {0}), Result(2));
83+
EXPECT_THAT(execute(*instance_reordered, 3, {0, 0}), Result());
7984

8085

8186
std::vector<ImportedFunction> imported_functions_extra = {
82-
{"mod1", "foo1", function_returning_value(0)},
83-
{"mod1", "foo2", function_returning_value(1)},
84-
{"mod2", "foo1", function_returning_value(2)},
85-
{"mod2", "foo2", function_returning_value(3)},
86-
{"mod3", "foo1", function_returning_value(4)},
87-
{"mod3", "foo2", function_returning_value(5)},
87+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
88+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
89+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
90+
{"mod2", "foo2", {ValType::i64, ValType::i32}, std::nullopt, function_returning_void},
91+
{"mod3", "foo1", {}, std::nullopt, function_returning_value(4)},
92+
{"mod3", "foo2", {}, std::nullopt, function_returning_value(5)},
8893
};
8994

9095
const auto external_functions_extra =
@@ -95,19 +100,55 @@ TEST(api, resolve_imported_functions)
95100
module, external_functions_extra, {}, {}, std::vector<ExternalGlobal>(external_globals));
96101

97102
EXPECT_THAT(execute(*instance_extra, 0, {}), Result(0));
98-
EXPECT_THAT(execute(*instance_extra, 1, {}), Result(1));
99-
EXPECT_THAT(execute(*instance_extra, 2, {}), Result(2));
100-
EXPECT_THAT(execute(*instance_extra, 3, {}), Result(3));
103+
EXPECT_THAT(execute(*instance_extra, 1, {0}), Result(1));
104+
EXPECT_THAT(execute(*instance_extra, 2, {0}), Result(2));
105+
EXPECT_THAT(execute(*instance_extra, 3, {0, 0}), Result());
101106

102107

103108
std::vector<ImportedFunction> imported_functions_missing = {
104-
{"mod1", "foo1", function_returning_value(0)},
105-
{"mod1", "foo2", function_returning_value(1)},
106-
{"mod2", "foo1", function_returning_value(2)},
109+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
110+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
111+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
107112
};
108113

109114
EXPECT_THROW_MESSAGE(resolve_imported_functions(module, std::move(imported_functions_missing)),
110115
instantiate_error, "imported function mod2.foo2 is required");
116+
117+
118+
std::vector<ImportedFunction> imported_functions_invalid_type1 = {
119+
{"mod1", "foo1", {ValType::i32}, ValType::i32, function_returning_value(0)},
120+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
121+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
122+
{"mod2", "foo2", {ValType::i64, ValType::i32}, std::nullopt, function_returning_void},
123+
};
124+
125+
EXPECT_THROW_MESSAGE(
126+
resolve_imported_functions(module, std::move(imported_functions_invalid_type1)),
127+
instantiate_error,
128+
"function mod1.foo1 input types don't match imported function in module");
129+
130+
std::vector<ImportedFunction> imported_functions_invalid_type2 = {
131+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
132+
{"mod1", "foo2", {ValType::i32}, ValType::i32, function_returning_value(1)},
133+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
134+
{"mod2", "foo2", {ValType::i64, ValType::i32}, ValType::i64, function_returning_value(3)},
135+
};
136+
137+
EXPECT_THROW_MESSAGE(
138+
resolve_imported_functions(module, std::move(imported_functions_invalid_type2)),
139+
instantiate_error, "function mod2.foo2 has output but is defined void in module");
140+
141+
std::vector<ImportedFunction> imported_functions_invalid_type3 = {
142+
{"mod1", "foo1", {}, ValType::i32, function_returning_value(0)},
143+
{"mod1", "foo2", {ValType::i32}, ValType::i64, function_returning_value(1)},
144+
{"mod2", "foo1", {ValType::i32}, ValType::i32, function_returning_value(2)},
145+
{"mod2", "foo2", {ValType::i64, ValType::i32}, std::nullopt, function_returning_void},
146+
};
147+
148+
EXPECT_THROW_MESSAGE(
149+
resolve_imported_functions(module, std::move(imported_functions_invalid_type3)),
150+
instantiate_error,
151+
"function mod1.foo2 output type doesn't match imported function in module");
111152
}
112153

113154
TEST(api, find_exported_function_index)

0 commit comments

Comments
 (0)