| // Copyright 2017 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. |
| |
| // Tests effects of (CSP) "unsafe-eval" and "wasm-eval" callback functions. |
| // |
| // Note: These tests are in a separate test file because the tests dynamically |
| // change the isolate in terms of callbacks allow_code_gen_callback and |
| // allow_wasm_code_gen_callback. |
| |
| #include "src/api/api-inl.h" |
| #include "src/wasm/wasm-module-builder.h" |
| #include "src/wasm/wasm-objects-inl.h" |
| #include "src/wasm/wasm-objects.h" |
| |
| #include "test/cctest/cctest.h" |
| #include "test/common/wasm/wasm-module-runner.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace wasm { |
| |
| namespace { |
| |
| // Possible values for callback pointers. |
| enum TestValue { |
| kTestUsingNull, // no callback. |
| kTestUsingFalse, // callback returning false. |
| kTestUsingTrue, // callbacl returning true. |
| }; |
| |
| constexpr int kNumTestValues = 3; |
| |
| const char* TestValueName[kNumTestValues] = {"null", "false", "true"}; |
| |
| // Defined to simplify iterating over TestValues; |
| const TestValue AllTestValues[kNumTestValues] = { |
| kTestUsingNull, kTestUsingFalse, kTestUsingTrue}; |
| |
| // This matrix holds the results of setting allow_code_gen_callback |
| // (first index) and allow_wasm_code_gen_callback (second index) using |
| // TestValue's. The value in the matrix is true if compilation is |
| // allowed, and false otherwise. |
| const bool ExpectedResults[kNumTestValues][kNumTestValues] = { |
| {true, false, true}, {false, false, true}, {true, false, true}}; |
| |
| bool TrueCallback(Local<v8::Context>, Local<v8::String>) { return true; } |
| |
| bool FalseCallback(Local<v8::Context>, Local<v8::String>) { return false; } |
| |
| using CallbackFn = bool (*)(Local<v8::Context>, Local<v8::String>); |
| |
| // Defines the Callback to use for the corresponding TestValue. |
| CallbackFn Callback[kNumTestValues] = {nullptr, FalseCallback, TrueCallback}; |
| |
| void BuildTrivialModule(Zone* zone, ZoneBuffer* buffer) { |
| WasmModuleBuilder* builder = zone->New<WasmModuleBuilder>(zone); |
| builder->WriteTo(buffer); |
| } |
| |
| bool TestModule(Isolate* isolate, v8::MemorySpan<const uint8_t> wire_bytes) { |
| HandleScope scope(isolate); |
| v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); |
| v8::Local<v8::Context> context = |
| Utils::ToLocal(Handle<Context>::cast(isolate->native_context())); |
| |
| // Get the "WebAssembly.Module" function. |
| auto get_property = [context, v8_isolate]( |
| v8::Local<v8::Object> obj, |
| const char* property_name) -> v8::Local<v8::Object> { |
| auto name = v8::String::NewFromUtf8(v8_isolate, property_name, |
| NewStringType::kInternalized) |
| .ToLocalChecked(); |
| return obj->Get(context, name).ToLocalChecked().As<v8::Object>(); |
| }; |
| auto wasm_class = get_property(context->Global(), "WebAssembly"); |
| auto module_class = get_property(wasm_class, "Module"); |
| |
| // Create an arraybuffer with the wire bytes. |
| v8::Local<v8::ArrayBuffer> buf = |
| v8::ArrayBuffer::New(v8_isolate, wire_bytes.size()); |
| memcpy(static_cast<uint8_t*>(buf->GetBackingStore()->Data()), |
| wire_bytes.data(), wire_bytes.size()); |
| |
| // Now call the "WebAssembly.Module" function with the array buffer. Return |
| // true if this succeeded, false otherwise. |
| v8::TryCatch try_catch(v8_isolate); |
| v8::Local<v8::Value> args[] = {buf}; |
| MaybeLocal<Value> module_object = |
| module_class->CallAsConstructor(context, arraysize(args), args); |
| |
| CHECK_EQ(try_catch.HasCaught(), module_object.IsEmpty()); |
| return !module_object.IsEmpty(); |
| } |
| |
| } // namespace |
| |
| TEST(PropertiesOfCodegenCallbacks) { |
| v8::internal::AccountingAllocator allocator; |
| Zone zone(&allocator, ZONE_NAME); |
| ZoneBuffer buffer(&zone); |
| BuildTrivialModule(&zone, &buffer); |
| v8::MemorySpan<const uint8_t> wire_bytes = {buffer.begin(), buffer.size()}; |
| Isolate* isolate = CcTest::InitIsolateOnce(); |
| HandleScope scope(isolate); |
| |
| for (TestValue codegen : AllTestValues) { |
| for (TestValue wasm_codegen : AllTestValues) { |
| fprintf(stderr, "Test codegen = %s, wasm_codegen = %s\n", |
| TestValueName[codegen], TestValueName[wasm_codegen]); |
| isolate->set_allow_code_gen_callback(Callback[codegen]); |
| isolate->set_allow_wasm_code_gen_callback(Callback[wasm_codegen]); |
| bool found = TestModule(isolate, wire_bytes); |
| bool expected = ExpectedResults[codegen][wasm_codegen]; |
| CHECK_EQ(expected, found); |
| CcTest::CollectAllAvailableGarbage(); |
| } |
| } |
| } |
| |
| TEST(WasmModuleObjectCompileFailure) { |
| const uint8_t wire_bytes_arr[] = {0xDE, 0xAD, 0xBE, 0xEF}; |
| v8::MemorySpan<const uint8_t> wire_bytes = {wire_bytes_arr, |
| arraysize(wire_bytes_arr)}; |
| Isolate* isolate = CcTest::InitIsolateOnce(); |
| HandleScope scope(isolate); |
| CHECK(!TestModule(isolate, wire_bytes)); |
| } |
| |
| } // namespace wasm |
| } // namespace internal |
| } // namespace v8 |