diff options
-rwxr-xr-x | scripts/test/lld.py | 14 | ||||
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 2 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 3 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 22 | ||||
-rw-r--r-- | test/lld/safe_stack_standalone-wasm.wat | 89 | ||||
-rw-r--r-- | test/lld/safe_stack_standalone-wasm.wat.out | 254 |
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 -- +;) |