// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "test/fuzzer/wasm/fuzzer-common.h" #include "include/v8-context.h" #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" #include "include/v8-metrics.h" #include "src/execution/isolate.h" #include "src/utils/ostreams.h" #include "src/wasm/baseline/liftoff-compiler.h" #include "src/wasm/compilation-environment-inl.h" #include "src/wasm/function-body-decoder-impl.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder-impl.h" #include "src/wasm/module-instantiate.h" #include "src/wasm/string-builder-multiline.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-feature-flags.h" #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes-inl.h" #include "src/zone/accounting-allocator.h" #include "src/zone/zone.h" #include "test/common/flag-utils.h" #include "test/common/wasm/wasm-module-runner.h" #include "test/fuzzer/fuzzer-support.h" #include "tools/wasm/mjsunit-module-disassembler-impl.h" #if V8_ENABLE_DRUMBRAKE #include "src/wasm/interpreter/wasm-interpreter.h" #endif // V8_ENABLE_DRUMBRAKE namespace v8::internal::wasm::fuzzing { namespace { void CompileAllFunctionsForReferenceExecution(NativeModule* native_module, int32_t* max_steps) { const WasmModule* module = native_module->module(); WasmCodeRefScope code_ref_scope; CompilationEnv env = CompilationEnv::ForModule(native_module); ModuleWireBytes wire_bytes_accessor{native_module->wire_bytes()}; for (size_t i = module->num_imported_functions; i < module->functions.size(); ++i) { auto& func = module->functions[i]; base::Vector func_code = wire_bytes_accessor.GetFunctionBytes(&func); constexpr bool kIsShared = false; FunctionBody func_body(func.sig, func.code.offset(), func_code.begin(), func_code.end(), kIsShared); auto result = ExecuteLiftoffCompilation(&env, func_body, LiftoffOptions{} .set_func_index(func.func_index) .set_for_debugging(kForDebugging) .set_max_steps(max_steps) .set_detect_nondeterminism(true)); if (!result.succeeded()) { FATAL( "Liftoff compilation failed on a valid module. Run with " "--trace-wasm-decoder (in a debug build) to see why."); } native_module->PublishCode(native_module->AddCompiledCode(result)); } } } // namespace CompileTimeImports CompileTimeImportsForFuzzing() { CompileTimeImports result; result.Add(CompileTimeImport::kJsString); result.Add(CompileTimeImport::kTextDecoder); result.Add(CompileTimeImport::kTextEncoder); return result; } // Compile a baseline module. We pass a pointer to a max step counter and a // nondeterminsm flag that are updated during execution by Liftoff. DirectHandle CompileReferenceModule( Isolate* isolate, base::Vector wire_bytes, int32_t* max_steps) { // Create the native module. std::shared_ptr native_module; constexpr bool kNoVerifyFunctions = false; auto enabled_features = WasmEnabledFeatures::FromIsolate(isolate); WasmDetectedFeatures detected_features; ModuleResult module_res = DecodeWasmModule(enabled_features, wire_bytes, kNoVerifyFunctions, ModuleOrigin::kWasmOrigin, &detected_features); CHECK(module_res.ok()); std::shared_ptr module = std::move(module_res).value(); CHECK_NOT_NULL(module); CompileTimeImports compile_imports = CompileTimeImportsForFuzzing(); WasmError imports_error = ValidateAndSetBuiltinImports( module.get(), wire_bytes, compile_imports, &detected_features); CHECK(!imports_error.has_error()); // The module was compiled before. const size_t code_size_estimate = WasmCodeManager::EstimateNativeModuleCodeSize(module.get()); native_module = GetWasmEngine()->NewNativeModule( isolate, enabled_features, detected_features, CompileTimeImportsForFuzzing(), module, code_size_estimate); native_module->SetWireBytes(base::OwnedCopyOf(wire_bytes)); // The module is known to be valid as this point (it was compiled by the // caller before). module->set_all_functions_validated(); // The value is -3 so that it is different than the compilation ID of actual // compilations, different than the sentinel value of the CompilationState // (-1) and the value used by native module deserialization (-2). const int dummy_fuzzing_compilation_id = -3; native_module->compilation_state()->set_compilation_id( dummy_fuzzing_compilation_id); InitializeCompilationForTesting(native_module.get()); // Compile all functions with Liftoff. CompileAllFunctionsForReferenceExecution(native_module.get(), max_steps); // Create the module object. constexpr base::Vector kNoSourceUrl; DirectHandle