// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains tests to exercise Wasm's in- and out- of bounds behavior.
const module_bytes = (function createModule() {
const builder = new WasmModuleBuilder;
builder.addImportedMemory("external", "memory");
const peek = builder.addFunction("peek", kSig_i_i).exportFunc();
peek.body
.get_local(0)
.i32_load()
.end();
const poke = builder.addFunction("poke", kSig_v_ii).exportFunc();
poke.body
.get_local(0)
.get_local(1)
.i32_store()
.end();
const grow = builder.addFunction("grow", kSig_i_i).exportFunc();
grow.body
.get_local(0)
.grow_memory()
.end();
return builder.toBuffer();
})();
function assert_true(b) {
if (!b) {
throw new Error("assert_true failed");
}
}
function assert_throws(error_class, f) {
try {
f()
} catch (e) {
if (e instanceof error_class) {
return;
}
}
throw new Error(
"function was expected to throw " + error_class + " but did not");
}
function assert_equals(actual, expected) {
if (actual != expected) {
throw new Error("Expected " + expected + " but got " + actual);
}
}
function instantiate(memory) {
assert_true(module_bytes instanceof ArrayBuffer,
"module bytes should be an ArrayBuffer");
assert_true(memory instanceof WebAssembly.Memory,
"memory must be a WebAssembly.Memory");
return new WebAssembly.Instance(
new WebAssembly.Module(module_bytes), { external: { memory: memory } });
}
function instantiatePages(num_pages) {
return instantiate(new WebAssembly.Memory({ initial: num_pages }));
}
function assert_oob(func) {
return assert_throws(WebAssembly.RuntimeError, func);
}
function peek_in_bounds() {
try {
const instance = instantiatePages(1);
const peek = instance.exports.peek;
assert_equals(peek(0), 0);
assert_equals(peek(10000), 0);
assert_equals(peek(65532), 0);
} catch(e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function peek_out_of_bounds() {
try {
const instance = instantiatePages(1);
const peek = instance.exports.peek;
assert_oob(_ => peek(65536));
assert_oob(_ => peek(65535));
assert_oob(_ => peek(65534));
assert_oob(_ => peek(65533));
assert_oob(_ => peek(1 << 30));
assert_oob(_ => peek(3 << 30));
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function peek_out_of_bounds_grow_memory_from_zero_js() {
const memory = new WebAssembly.Memory({initial: 0});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
assert_oob(_ => peek(0));
memory.grow(1);
assert_equals(peek(0), 0);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function peek_out_of_bounds_grow_memory_js() {
const memory = new WebAssembly.Memory({initial: 1});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
assert_oob(_ => peek(70000));
memory.grow(1);
assert_equals(peek(70000), 0);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function peek_out_of_bounds_grow_memory_from_zero_wasm() {
const memory = new WebAssembly.Memory({initial: 0});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const grow = instance.exports.grow;
assert_oob(_ => peek(0));
grow(1);
assert_equals(peek(0), 0);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function peek_out_of_bounds_grow_memory_wasm() {
const memory = new WebAssembly.Memory({initial: 1});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const grow = instance.exports.grow;
assert_oob(_ => peek(70000));
grow(1);
assert_equals(peek(70000), 0);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_in_bounds() {
try {
const instance = instantiatePages(1);
const peek = instance.exports.peek;
const poke = instance.exports.poke;
poke(0, 41);
poke(10000, 42);
poke(65532, 43);
assert_equals(peek(0), 41);
assert_equals(peek(10000), 42);
assert_equals(peek(65532), 43);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_out_of_bounds() {
try {
const instance = instantiatePages(1);
const poke = instance.exports.poke;
assert_oob(_ => poke(65536, 0));
assert_oob(_ => poke(65535, 0));
assert_oob(_ => poke(65534, 0));
assert_oob(_ => poke(65533, 0));
assert_oob(_ => poke(1 << 30, 0));
assert_oob(_ => poke(3 << 30, 0));
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_out_of_bounds_grow_memory_from_zero_js() {
const memory = new WebAssembly.Memory({initial: 0});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const poke = instance.exports.poke;
function check_poke(index, value) {
poke(index, value);
assert_equals(peek(index), value);
}
assert_oob(_ => poke(0, 42));
memory.grow(1);
check_poke(0, 42);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_out_of_bounds_grow_memory_js() {
const memory = new WebAssembly.Memory({initial: 1});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const poke = instance.exports.poke;
function check_poke(index, value) {
poke(index, value);
assert_equals(peek(index), value);
}
assert_oob(_ => poke(70000, 42));
memory.grow(1);
check_poke(70000, 42);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_out_of_bounds_grow_memory_from_zero_wasm() {
const memory = new WebAssembly.Memory({initial: 0});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const poke = instance.exports.poke;
const grow = instance.exports.grow;
function check_poke(index, value) {
poke(index, value);
assert_equals(peek(index), value);
}
assert_oob(_ => poke(0, 42));
grow(1);
check_poke(0, 42);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}
function poke_out_of_bounds_grow_memory_wasm() {
const memory = new WebAssembly.Memory({initial: 1});
try {
const instance = instantiate(memory);
const peek = instance.exports.peek;
const poke = instance.exports.poke;
const grow = instance.exports.grow;
function check_poke(index, value) {
poke(index, value);
assert_equals(peek(index), value);
}
assert_oob(_ => poke(70000, 42));
grow(1);
check_poke(70000, 42);
} catch (e) {
console.error("uncaught exception: " + e);
return false;
}
return true;
}