Commit 272e5a87 authored by Andreas Haas's avatar Andreas Haas Committed by V8 LUCI CQ

[wasm] Do not serialize modules that don't contain TurboFan code

The wasm serialization format only contains TurboFan code. All other
functions are only represented by placeholders. With this CL
serialization fails if the serialized module does not contain any
TurboFan functions and would therefore consist only of placeholders.

This is a defense in depth approach, because ideally serialization
only gets triggered when TurboFan code is available. However, in some
scenarios like debugging it can happen that modules without TurboFan
code get serialized.

Bug: v8:12281
Change-Id: Ib05430ff89eb2317da80fc0d086ce1d7ab0e919d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3212510
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77715}
parent d44788a6
......@@ -291,6 +291,7 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer {
const base::Vector<WasmCode* const> code_table_;
bool write_called_ = false;
size_t total_written_code_ = 0;
int num_turbofan_functions_ = 0;
};
NativeModuleSerializer::NativeModuleSerializer(
......@@ -341,6 +342,7 @@ bool NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
writer->Write(false);
return true;
}
++num_turbofan_functions_;
writer->Write(true);
// Write the size of the entire code section, followed by the code header.
writer->Write(code->constant_pool_offset());
......@@ -449,6 +451,8 @@ bool NativeModuleSerializer::Write(Writer* writer) {
for (WasmCode* code : code_table_) {
if (!WriteCode(code, writer)) return false;
}
// If not a single function was written, serialization was not successful.
if (num_turbofan_functions_ == 0) return false;
// Make sure that the serialized total code size was correct.
CHECK_EQ(total_written_code_, total_code_size);
......
......@@ -330,6 +330,36 @@ TEST(TierDownAfterDeserialization) {
CHECK_EQ(ExecutionTier::kLiftoff, liftoff_code->tier());
}
TEST(SerializeLiftoffModuleFails) {
// Make sure that no function is tiered up to TurboFan.
if (!FLAG_liftoff) return;
FlagScope<bool> no_tier_up(&FLAG_wasm_tier_up, false);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, "test_zone");
CcTest::InitIsolateOnce();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
ZoneBuffer wire_bytes_buffer(&zone);
WasmSerializationTest::BuildWireBytes(&zone, &wire_bytes_buffer);
ErrorThrower thrower(isolate, "Test");
MaybeHandle<WasmModuleObject> maybe_module_object =
GetWasmEngine()->SyncCompile(
isolate, WasmFeatures::All(), &thrower,
ModuleWireBytes(wire_bytes_buffer.begin(), wire_bytes_buffer.end()));
Handle<WasmModuleObject> module_object =
maybe_module_object.ToHandleChecked();
NativeModule* native_module = module_object->native_module();
WasmSerializer wasm_serializer(native_module);
size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize();
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
// Serialization is expected to fail if there is no TurboFan function to
// serialize.
CHECK(!wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size}));
}
} // namespace test_wasm_serialization
} // namespace wasm
} // namespace internal
......
......@@ -2,17 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The test needs --wasm-tier-up because we can't serialize and deserialize
// The test needs --no-liftoff because we can't serialize and deserialize
// Liftoff code.
// Flags: --expose-wasm --allow-natives-syntax --expose-gc --wasm-tier-up
// Flags: --expose-wasm --allow-natives-syntax --expose-gc --no-liftoff
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
const num_functions = 3;
const wire_bytes = new WasmModuleBuilder().toBuffer();
function create_builder() {
const builder = new WasmModuleBuilder();
for (let i = 0; i < num_functions; ++i) {
builder.addFunction('f' + i, kSig_i_v)
.addBody(wasmI32Const(i))
.exportFunc();
}
return builder;
}
const wire_bytes = create_builder().toBuffer();
const serialized = (() => {
return %SerializeWasmModule(new WebAssembly.Module(wire_bytes));
const module = new WebAssembly.Module(wire_bytes);
const instance = new WebAssembly.Instance(module);
// Run one function so that serialization happens.
instance.exports.f2();
return %SerializeWasmModule(module);
})();
// Collect the compiled module, to avoid sharing of the NativeModule.
......
......@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The test needs --no-liftoff because we can't serialize and deserialize
// Liftoff code.
// Flags: --wasm-lazy-compilation --allow-natives-syntax --expose-gc
// Flags: --no-liftoff
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
......@@ -20,8 +23,11 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
const wire_bytes = builder.toBuffer();
const module = new WebAssembly.Module(wire_bytes);
// Run one function so that serialization happens.
let instance = new WebAssembly.Instance(module);
instance.exports.f3();
const buff = %SerializeWasmModule(module);
return [wire_bytes, new WebAssembly.Instance(module), buff];
return [wire_bytes, instance, buff];
})();
gc();
......@@ -47,8 +53,10 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
const wire_bytes = builder.toBuffer();
const module = new WebAssembly.Module(wire_bytes);
const buff = %SerializeWasmModule(module);
const i1 = new WebAssembly.Instance(module);
// Run one function so that serialization happens.
i1.exports.f3();
const buff = %SerializeWasmModule(module);
assertEquals(2, i1.exports.f2());
assertEquals(11, i1.exports.f11());
......
......@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The test needs --no-liftoff because we can't serialize and deserialize
// Liftoff code.
// Flags: --allow-natives-syntax --wasm-lazy-compilation --expose-gc
// Flags: --no-liftoff
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
const num_functions = 2;
const num_functions = 3;
function create_builder() {
const builder = new WasmModuleBuilder();
......@@ -23,6 +26,9 @@ const wire_bytes = create_builder().toBuffer();
function serializeModule() {
const module = new WebAssembly.Module(wire_bytes);
// Run one function so that serialization happens.
let instance = new WebAssembly.Instance(module, {foo: {bar: () => 1}});
instance.exports.f2();
const buff = %SerializeWasmModule(module);
return buff;
};
......
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