blob: 30f5d48a07be40a98b82a5218b0489fcdffe1c7b [file] [log] [blame]
Ben Murdochc5610432016-08-08 18:44:38 +01001// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/wasm/wasm-macro-gen.h"
6
7#include "test/cctest/cctest.h"
8#include "test/cctest/compiler/value-helper.h"
9#include "test/cctest/wasm/test-signatures.h"
10#include "test/cctest/wasm/wasm-run-utils.h"
11
12using namespace v8::base;
13using namespace v8::internal;
14using namespace v8::internal::compiler;
15using namespace v8::internal::wasm;
16
17using v8::Local;
18using v8::Utils;
19
20namespace {
21
22#define CHECK_CSTREQ(exp, found) \
23 do { \
24 const char* exp_ = (exp); \
25 const char* found_ = (found); \
26 DCHECK_NOT_NULL(exp); \
27 if (V8_UNLIKELY(found_ == nullptr || strcmp(exp_, found_) != 0)) { \
28 V8_Fatal(__FILE__, __LINE__, \
29 "Check failed: (%s) != (%s) ('%s' vs '%s').", #exp, #found, \
30 exp_, found_ ? found_ : "<null>"); \
31 } \
32 } while (0)
33
34struct ExceptionInfo {
35 const char* func_name;
36 int line_nr;
37 int column;
38};
39
40template <int N>
Ben Murdoch61f157c2016-09-16 13:49:30 +010041void CheckExceptionInfos(Handle<Object> exc,
Ben Murdochc5610432016-08-08 18:44:38 +010042 const ExceptionInfo (&excInfos)[N]) {
43 // Check that it's indeed an Error object.
Ben Murdoch61f157c2016-09-16 13:49:30 +010044 CHECK(exc->IsJSError());
Ben Murdochc5610432016-08-08 18:44:38 +010045
46 // Extract stack frame from the exception.
47 Local<v8::Value> localExc = Utils::ToLocal(exc);
48 v8::Local<v8::StackTrace> stack = v8::Exception::GetStackTrace(localExc);
49 CHECK(!stack.IsEmpty());
50 CHECK_EQ(N, stack->GetFrameCount());
51
52 for (int frameNr = 0; frameNr < N; ++frameNr) {
53 v8::Local<v8::StackFrame> frame = stack->GetFrame(frameNr);
54 v8::String::Utf8Value funName(frame->GetFunctionName());
55 CHECK_CSTREQ(excInfos[frameNr].func_name, *funName);
56 CHECK_EQ(excInfos[frameNr].line_nr, frame->GetLineNumber());
57 CHECK_EQ(excInfos[frameNr].column, frame->GetColumn());
58 }
59}
60
61} // namespace
62
63// Trigger a trap for executing unreachable.
64TEST(Unreachable) {
65 TestSignatures sigs;
66 TestingModule module;
67
68 WasmFunctionCompiler comp1(sigs.v_v(), &module,
69 ArrayVector("exec_unreachable"));
70 // Set the execution context, such that a runtime error can be thrown.
71 comp1.SetModuleContext();
72 BUILD(comp1, WASM_UNREACHABLE);
73 uint32_t wasm_index = comp1.CompileAndAdd();
74
75 Handle<JSFunction> js_wasm_wrapper = module.WrapCode(wasm_index);
76
77 Handle<JSFunction> js_trampoline = Handle<JSFunction>::cast(
78 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
79 CompileRun("(function callFn(fn) { fn(); })"))));
80
81 Isolate* isolate = js_wasm_wrapper->GetIsolate();
82 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
83 v8::StackTrace::kOverview);
84 Handle<Object> global(isolate->context()->global_object(), isolate);
85 MaybeHandle<Object> maybe_exc;
86 Handle<Object> args[] = {js_wasm_wrapper};
87 MaybeHandle<Object> returnObjMaybe =
88 Execution::TryCall(isolate, js_trampoline, global, 1, args, &maybe_exc);
89 CHECK(returnObjMaybe.is_null());
90
Ben Murdoch61f157c2016-09-16 13:49:30 +010091 // The column is 1-based, so add 1 to the actual byte offset.
Ben Murdochc5610432016-08-08 18:44:38 +010092 ExceptionInfo expected_exceptions[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +010093 {"<WASM UNNAMED>", static_cast<int>(wasm_index), 2}, // --
94 {"callFn", 1, 24} // --
Ben Murdochc5610432016-08-08 18:44:38 +010095 };
Ben Murdoch61f157c2016-09-16 13:49:30 +010096 CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
Ben Murdochc5610432016-08-08 18:44:38 +010097}
98
99// Trigger a trap for loading from out-of-bounds.
100TEST(IllegalLoad) {
101 TestSignatures sigs;
102 TestingModule module;
103
104 WasmFunctionCompiler comp1(sigs.v_v(), &module, ArrayVector("mem_oob"));
105 // Set the execution context, such that a runtime error can be thrown.
106 comp1.SetModuleContext();
107 BUILD(comp1, WASM_IF(WASM_ONE,
108 WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(-3))));
109 uint32_t wasm_index = comp1.CompileAndAdd();
110
111 WasmFunctionCompiler comp2(sigs.v_v(), &module, ArrayVector("call_mem_oob"));
112 // Insert a NOP such that the position of the call is not one.
113 BUILD(comp2, WASM_NOP, WASM_CALL_FUNCTION0(wasm_index));
114 uint32_t wasm_index_2 = comp2.CompileAndAdd();
115
116 Handle<JSFunction> js_wasm_wrapper = module.WrapCode(wasm_index_2);
117
118 Handle<JSFunction> js_trampoline = Handle<JSFunction>::cast(
119 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
120 CompileRun("(function callFn(fn) { fn(); })"))));
121
122 Isolate* isolate = js_wasm_wrapper->GetIsolate();
123 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
124 v8::StackTrace::kOverview);
125 Handle<Object> global(isolate->context()->global_object(), isolate);
126 MaybeHandle<Object> maybe_exc;
127 Handle<Object> args[] = {js_wasm_wrapper};
128 MaybeHandle<Object> returnObjMaybe =
129 Execution::TryCall(isolate, js_trampoline, global, 1, args, &maybe_exc);
130 CHECK(returnObjMaybe.is_null());
131
Ben Murdoch61f157c2016-09-16 13:49:30 +0100132 // The column is 1-based, so add 1 to the actual byte offset.
Ben Murdochc5610432016-08-08 18:44:38 +0100133 ExceptionInfo expected_exceptions[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100134 {"<WASM UNNAMED>", static_cast<int>(wasm_index), 7}, // --
135 {"<WASM UNNAMED>", static_cast<int>(wasm_index_2), 3}, // --
136 {"callFn", 1, 24} // --
Ben Murdochc5610432016-08-08 18:44:38 +0100137 };
Ben Murdoch61f157c2016-09-16 13:49:30 +0100138 CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
Ben Murdochc5610432016-08-08 18:44:38 +0100139}