Commit e79760c9 authored by Ben Smith's avatar Ben Smith Committed by Commit Bot

[wasm] Fail validation with non-zero functions, but no code section

Make sure to check that the number of declared functions (specified in the
function section) matches the number of function bodies, even if the code
section is omitted.

Note that it is valid to have a function section with zero declared functions
and an omitted code section, and vice versa.

Bug: v8:8514
Change-Id: I4effa5abe2ed6d71146a665d2df6a2f48b5a84be
Reviewed-on: https://chromium-review.googlesource.com/c/1351306
Commit-Queue: Ben Smith <binji@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57949}
parent cb242ede
......@@ -2899,7 +2899,10 @@ void AsyncStreamingProcessor::OnFinishedChunk() {
void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
TRACE_STREAMING("Finish stream...\n");
ModuleResult result = decoder_.FinishDecoding(false);
DCHECK(result.ok());
if (result.failed()) {
FinishAsyncCompileJobWithError(std::move(result));
return;
}
bool needs_finish = job_->DecrementAndCheckFinisherCount();
if (job_->native_module_ == nullptr) {
// We are processing a WebAssembly module without code section. Create the
......
......@@ -935,7 +935,23 @@ class ModuleDecoderImpl : public Decoder {
ModuleResult FinishDecoding(bool verify_functions = true) {
if (ok()) {
CalculateGlobalOffsets(module_.get());
// The declared vs. defined function count is normally checked when
// decoding the code section, but we have to check it here too in case the
// code section is absent.
if (module_->num_declared_functions != 0) {
DCHECK_LT(module_->num_imported_functions, module_->functions.size());
// We know that the code section has been decoded if the first
// non-imported function has its code set.
if (!module_->functions[module_->num_imported_functions]
.code.is_set()) {
errorf(pc(), "function count is %u, but code section is absent",
module_->num_declared_functions);
}
}
if (ok()) {
CalculateGlobalOffsets(module_.get());
}
}
ModuleResult result = toResult(std::move(module_));
if (verify_functions && result.ok() && intermediate_result_.failed()) {
......
......@@ -1086,6 +1086,32 @@ STREAM_TEST(TestDeserializationFails) {
CHECK(tester.IsPromiseFulfilled());
}
// Test that a non-empty function section with a missing code section fails.
STREAM_TEST(TestFunctionSectionWithoutCodeSection) {
StreamTester tester;
const uint8_t bytes[] = {
WASM_MODULE_HEADER, // module header
kTypeSectionCode, // section code
U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
U32V_1(1), // type count
SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
kFunctionSectionCode, // section code
U32V_1(1 + 3), // section size
U32V_1(3), // functions count
0, // signature index
0, // signature index
0, // signature index
};
tester.OnBytesReceived(bytes, arraysize(bytes));
tester.FinishStream();
tester.RunCompilerTasks();
CHECK(tester.IsPromiseRejected());
}
#undef STREAM_TEST
} // namespace wasm
......
......@@ -860,7 +860,9 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
// funcs ---------------------------------------------------------------
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
// table declaration ---------------------------------------------------
SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1)};
SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1),
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
......@@ -945,7 +947,9 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction_one_entry) {
ENTRY_COUNT(1), // entry count
TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0),
1, // elements count
FUNC_INDEX(0))};
FUNC_INDEX(0)),
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
......@@ -1009,7 +1013,8 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
};
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_VERIFIES(data);
}
......@@ -1063,7 +1068,8 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
};
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_VERIFIES(data);
}
......@@ -1098,7 +1104,8 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
WASM_INIT_EXPR_I32V_1(3), // index
1, // elements count
FUNC_INDEX(0)), // function
};
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_VERIFIES(data);
}
......@@ -1152,7 +1159,8 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
2, // elements count
FUNC_INDEX(0), // entry 0
FUNC_INDEX(0)), // entry 1
};
// code ----------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_VERIFIES(data);
}
......@@ -1885,20 +1893,6 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
EXPECT_OFF_END_FAILURE(data, arraysize(data) - 3);
}
TEST_F(WasmModuleVerifyTest, FunctionSignatures_empty) {
static const byte data[] = {SECTION(Type, ENTRY_COUNT(0)),
SECTION(Function, ENTRY_COUNT(0))};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionSignatures_one) {
static const byte data[] = {
SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // --
FUNCTION_SIGNATURES_SECTION(1, 0) // --
};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, Regression_648070) {
static const byte data[] = {
SECTION(Type, ENTRY_COUNT(0)), // --
......@@ -2041,6 +2035,31 @@ TEST_F(WasmModuleVerifyTest, Regression684855) {
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionSectionWithoutCodeSection) {
static const byte data[] = {
SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // Type section.
FUNCTION_SIGNATURES_SECTION(1, 0), // Function section.
};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result, "function count is 1, but code section is absent");
}
TEST_F(WasmModuleVerifyTest, CodeSectionWithoutFunctionSection) {
static const byte data[] = {ONE_EMPTY_BODY};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result, "function body count 1 mismatch (0 expected)");
}
TEST_F(WasmModuleVerifyTest, EmptyFunctionSectionWithoutCodeSection) {
static const byte data[] = {SECTION(Function, ENTRY_COUNT(0))};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, EmptyCodeSectionWithoutFunctionSection) {
static const byte data[] = {SECTION(Code, ENTRY_COUNT(0))};
EXPECT_VERIFIES(data);
}
class WasmInitExprDecodeTest : public TestWithZone {
public:
WasmInitExprDecodeTest() = default;
......@@ -2243,7 +2262,8 @@ TEST_F(WasmModuleVerifyTest, PassiveElementSegment) {
// element segments -----------------------------------------------------
SECTION(Element, ENTRY_COUNT(1), PASSIVE,
ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(0))),
};
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_FAILURE(data);
WASM_FEATURE_SCOPE(bulk_memory);
EXPECT_VERIFIES(data);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment