chromium/chrome/test/data/wasm/out_of_bounds.js

// 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;
}