Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions scripts/test/lld.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@


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():
Expand Down
2 changes: 2 additions & 0 deletions src/tools/wasm-emscripten-finalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ int main(int argc, const char* argv[]) {
}

EmscriptenGlueGenerator generator(wasm);
generator.setStandalone(standaloneWasm);

generator.fixInvokeFunctionNames();

std::vector<Name> initializerFunctions;
Expand Down
3 changes: 3 additions & 0 deletions src/wasm-emscripten.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class EmscriptenGlueGenerator {
: wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
useStackPointerGlobal(stackPointerOffset == 0) {}

void setStandalone(bool standalone_) { standalone = standalone_; }

void generateRuntimeFunctions();
Function* generateMemoryGrowthFunction();
Function* generateAssignGOTEntriesFunction();
Expand Down Expand Up @@ -69,6 +71,7 @@ class EmscriptenGlueGenerator {
Builder builder;
Address stackPointerOffset;
bool useStackPointerGlobal;
bool standalone;
// Used by generateDynCallThunk to track all the dynCall functions created
// so far.
std::unordered_set<std::string> sigs;
Expand Down
22 changes: 17 additions & 5 deletions src/wasm/wasm-emscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,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),
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));
Expand Down Expand Up @@ -534,8 +541,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);
Expand All @@ -553,6 +559,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)) {
Expand Down
89 changes: 89 additions & 0 deletions test/lld/safe_stack_standalone-wasm.wat
Original file line number Diff line number Diff line change
@@ -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)
)
)

Loading