summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/test/lld.py14
-rw-r--r--src/tools/wasm-emscripten-finalize.cpp2
-rw-r--r--src/wasm-emscripten.h3
-rw-r--r--src/wasm/wasm-emscripten.cpp22
-rw-r--r--test/lld/safe_stack_standalone-wasm.wat89
-rw-r--r--test/lld/safe_stack_standalone-wasm.wat.out254
6 files changed, 372 insertions, 12 deletions
diff --git a/scripts/test/lld.py b/scripts/test/lld.py
index f509059de..992a35655 100755
--- a/scripts/test/lld.py
+++ b/scripts/test/lld.py
@@ -19,14 +19,14 @@ from . import support
def args_for_finalize(filename):
+ ret = ['--global-base=568']
if 'safe_stack' in filename:
- return ['--check-stack-overflow', '--global-base=568']
- elif 'shared' in filename:
- return ['--side-module']
- elif 'standalone-wasm' in filename:
- return ['--standalone-wasm', '--global-base=568']
- else:
- return ['--global-base=568']
+ ret += ['--check-stack-overflow']
+ if 'shared' in filename:
+ ret += ['--side-module']
+ if 'standalone-wasm' in filename:
+ ret += ['--standalone-wasm']
+ return ret
def test_wasm_emscripten_finalize():
diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp
index f569b54cb..b45b61b8f 100644
--- a/src/tools/wasm-emscripten-finalize.cpp
+++ b/src/tools/wasm-emscripten-finalize.cpp
@@ -207,6 +207,8 @@ int main(int argc, const char* argv[]) {
}
EmscriptenGlueGenerator generator(wasm);
+ generator.setStandalone(standaloneWasm);
+
generator.fixInvokeFunctionNames();
std::vector<Name> initializerFunctions;
diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h
index 8aa911ef9..c7689b4bc 100644
--- a/src/wasm-emscripten.h
+++ b/src/wasm-emscripten.h
@@ -31,6 +31,8 @@ public:
: wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
useStackPointerGlobal(stackPointerOffset == 0) {}
+ void setStandalone(bool standalone_) { standalone = standalone_; }
+
void generateRuntimeFunctions();
Function* generateMemoryGrowthFunction();
Function* generateAssignGOTEntriesFunction();
@@ -69,6 +71,7 @@ private:
Builder builder;
Address stackPointerOffset;
bool useStackPointerGlobal;
+ bool standalone;
// Used by generateDynCallThunk to track all the dynCall functions created
// so far.
std::unordered_set<Signature> sigs;
diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp
index be4e51b9e..f069e558d 100644
--- a/src/wasm/wasm-emscripten.cpp
+++ b/src/wasm/wasm-emscripten.cpp
@@ -103,18 +103,25 @@ inline Expression* stackBoundsCheck(Builder& builder,
Expression* value,
Global* stackPointer,
Global* stackLimit,
- Name handler) {
+ Name handlerName) {
// Add a local to store the value of the expression. We need the value twice:
// once to check if it has overflowed, and again to assign to store it.
auto newSP = Builder::addVar(func, stackPointer->type);
+ // If we imported a handler, call it. That can show a nice error in JS.
+ // Otherwise, just trap.
+ Expression* handler;
+ if (handlerName.is()) {
+ handler = builder.makeCall(handlerName, {}, none);
+ } else {
+ handler = builder.makeUnreachable();
+ }
// (if (i32.lt_u (local.tee $newSP (...value...)) (global.get $__stack_limit))
- // (call $handler))
auto check =
builder.makeIf(builder.makeBinary(
BinaryOp::LtUInt32,
builder.makeLocalTee(newSP, value, stackPointer->type),
builder.makeGlobalGet(stackLimit->name, stackLimit->type)),
- builder.makeCall(handler, {}, none));
+ handler);
// (global.set $__stack_pointer (local.get $newSP))
auto newSet = builder.makeGlobalSet(
stackPointer->name, builder.makeLocalGet(newSP, stackPointer->type));
@@ -530,8 +537,7 @@ void EmscriptenGlueGenerator::enforceStackLimit() {
Builder::Mutable);
wasm.addGlobal(stackLimit);
- auto handler = importStackOverflowHandler();
-
+ Name handler = importStackOverflowHandler();
StackLimitEnforcer walker(stackPointer, stackLimit, builder, handler);
PassRunner runner(&wasm);
walker.run(&runner, &wasm);
@@ -549,6 +555,12 @@ void EmscriptenGlueGenerator::generateSetStackLimitFunction() {
}
Name EmscriptenGlueGenerator::importStackOverflowHandler() {
+ // We can call an import to handle stack overflows normally, but not in
+ // standalone mode, where we can't import from JS.
+ if (standalone) {
+ return Name();
+ }
+
ImportInfo info(wasm);
if (auto* existing = info.getImportedFunction(ENV, STACK_OVERFLOW_IMPORT)) {
diff --git a/test/lld/safe_stack_standalone-wasm.wat b/test/lld/safe_stack_standalone-wasm.wat
new file mode 100644
index 000000000..e2d8a79de
--- /dev/null
+++ b/test/lld/safe_stack_standalone-wasm.wat
@@ -0,0 +1,89 @@
+(module
+ (type $0 (func (param i32 i32) (result i32)))
+ (type $1 (func))
+ (type $2 (func (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (data (i32.const 568) "%d:%d\n\00Result: %d\n\00")
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 66128))
+ (global $global$1 i32 (i32.const 66128))
+ (global $global$2 i32 (i32.const 587))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors (; 1 ;) (type $1)
+ )
+ (func $foo (; 2 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (global.set $global$0
+ (local.tee $2
+ (i32.sub
+ (global.get $global$0)
+ (i32.const 16)
+ )
+ )
+ )
+ (i32.store offset=4
+ (local.get $2)
+ (local.get $1)
+ )
+ (i32.store
+ (local.get $2)
+ (local.get $0)
+ )
+ (drop
+ (call $printf
+ (i32.const 568)
+ (local.get $2)
+ )
+ )
+ (global.set $global$0
+ (i32.add
+ (local.get $2)
+ (i32.const 16)
+ )
+ )
+ (i32.add
+ (local.get $1)
+ (local.get $0)
+ )
+ )
+ (func $__original_main (; 3 ;) (type $2) (result i32)
+ (local $0 i32)
+ (global.set $global$0
+ (local.tee $0
+ (i32.sub
+ (global.get $global$0)
+ (i32.const 16)
+ )
+ )
+ )
+ (i32.store
+ (local.get $0)
+ (call $foo
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (drop
+ (call $printf
+ (i32.const 575)
+ (local.get $0)
+ )
+ )
+ (global.set $global$0
+ (i32.add
+ (local.get $0)
+ (i32.const 16)
+ )
+ )
+ (i32.const 0)
+ )
+ (func $main (; 4 ;) (type $0) (param $0 i32) (param $1 i32) (result i32)
+ (call $__original_main)
+ )
+)
+
diff --git a/test/lld/safe_stack_standalone-wasm.wat.out b/test/lld/safe_stack_standalone-wasm.wat.out
new file mode 100644
index 000000000..3632831ac
--- /dev/null
+++ b/test/lld/safe_stack_standalone-wasm.wat.out
@@ -0,0 +1,254 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "printf" (func $printf (param i32 i32) (result i32)))
+ (memory $0 2)
+ (data (i32.const 568) "%d:%d\n\00Result: %d\n\00")
+ (table $0 1 1 funcref)
+ (global $global$0 (mut i32) (i32.const 66128))
+ (global $global$1 i32 (i32.const 66128))
+ (global $global$2 i32 (i32.const 587))
+ (global $__stack_limit (mut i32) (i32.const 0))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "__heap_base" (global $global$1))
+ (export "__data_end" (global $global$2))
+ (export "main" (func $main))
+ (export "__set_stack_limit" (func $__set_stack_limit))
+ (export "stackSave" (func $stackSave))
+ (export "stackAlloc" (func $stackAlloc))
+ (export "stackRestore" (func $stackRestore))
+ (export "__growWasmMemory" (func $__growWasmMemory))
+ (export "_start" (func $_start))
+ (func $__wasm_call_ctors (; 1 ;)
+ (nop)
+ )
+ (func $foo (; 2 ;) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (block
+ (if
+ (i32.lt_u
+ (local.tee $3
+ (local.tee $2
+ (i32.sub
+ (global.get $global$0)
+ (i32.const 16)
+ )
+ )
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $3)
+ )
+ )
+ (i32.store offset=4
+ (local.get $2)
+ (local.get $1)
+ )
+ (i32.store
+ (local.get $2)
+ (local.get $0)
+ )
+ (drop
+ (call $printf
+ (i32.const 568)
+ (local.get $2)
+ )
+ )
+ (block
+ (if
+ (i32.lt_u
+ (local.tee $4
+ (i32.add
+ (local.get $2)
+ (i32.const 16)
+ )
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $4)
+ )
+ )
+ (i32.add
+ (local.get $1)
+ (local.get $0)
+ )
+ )
+ (func $__original_main (; 3 ;) (result i32)
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (block
+ (if
+ (i32.lt_u
+ (local.tee $1
+ (local.tee $0
+ (i32.sub
+ (global.get $global$0)
+ (i32.const 16)
+ )
+ )
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $1)
+ )
+ )
+ (i32.store
+ (local.get $0)
+ (call $foo
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (drop
+ (call $printf
+ (i32.const 575)
+ (local.get $0)
+ )
+ )
+ (block
+ (if
+ (i32.lt_u
+ (local.tee $2
+ (i32.add
+ (local.get $0)
+ (i32.const 16)
+ )
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $2)
+ )
+ )
+ (i32.const 0)
+ )
+ (func $main (; 4 ;) (param $0 i32) (param $1 i32) (result i32)
+ (call $__original_main)
+ )
+ (func $__set_stack_limit (; 5 ;) (param $0 i32)
+ (global.set $__stack_limit
+ (local.get $0)
+ )
+ )
+ (func $stackSave (; 6 ;) (result i32)
+ (global.get $global$0)
+ )
+ (func $stackAlloc (; 7 ;) (param $0 i32) (result i32)
+ (local $1 i32)
+ (local $2 i32)
+ (block
+ (if
+ (i32.lt_u
+ (local.tee $2
+ (local.tee $1
+ (i32.and
+ (i32.sub
+ (global.get $global$0)
+ (local.get $0)
+ )
+ (i32.const -16)
+ )
+ )
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $2)
+ )
+ )
+ (local.get $1)
+ )
+ (func $stackRestore (; 8 ;) (param $0 i32)
+ (local $1 i32)
+ (if
+ (i32.lt_u
+ (local.tee $1
+ (local.get $0)
+ )
+ (global.get $__stack_limit)
+ )
+ (unreachable)
+ )
+ (global.set $global$0
+ (local.get $1)
+ )
+ )
+ (func $__growWasmMemory (; 9 ;) (param $newSize i32) (result i32)
+ (memory.grow
+ (local.get $newSize)
+ )
+ )
+ (func $_start (; 10 ;)
+ (drop
+ (call $main
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ )
+)
+(;
+--BEGIN METADATA --
+{
+ "staticBump": 19,
+ "tableSize": 1,
+ "initializers": [
+ "__wasm_call_ctors"
+ ],
+ "declares": [
+ "printf"
+ ],
+ "externs": [
+ ],
+ "implementedFunctions": [
+ "___wasm_call_ctors",
+ "_main",
+ "___set_stack_limit",
+ "_stackSave",
+ "_stackAlloc",
+ "_stackRestore",
+ "___growWasmMemory",
+ "__start"
+ ],
+ "exports": [
+ "__wasm_call_ctors",
+ "main",
+ "__set_stack_limit",
+ "stackSave",
+ "stackAlloc",
+ "stackRestore",
+ "__growWasmMemory",
+ "_start"
+ ],
+ "namedGlobals": {
+ "__heap_base" : "66128",
+ "__data_end" : "587"
+ },
+ "invokeFuncs": [
+ ],
+ "features": [
+ ],
+ "mainReadsParams": 0
+}
+-- END METADATA --
+;)