diff options
-rw-r--r-- | src/passes/StackCheck.cpp | 61 | ||||
-rw-r--r-- | test/passes/stack-check_enable-mutable-globals.txt | 22 | ||||
-rw-r--r-- | test/passes/stack-check_enable-mutable-globals.wast | 10 |
3 files changed, 62 insertions, 31 deletions
diff --git a/src/passes/StackCheck.cpp b/src/passes/StackCheck.cpp index c25d70635..23fd5be3d 100644 --- a/src/passes/StackCheck.cpp +++ b/src/passes/StackCheck.cpp @@ -22,6 +22,7 @@ #include "abi/js.h" #include "ir/import-utils.h" +#include "ir/names.h" #include "pass.h" #include "shared-constants.h" #include "support/debug.h" @@ -31,11 +32,6 @@ namespace wasm { -// The base is where the stack begins. As it goes down, that is the highest -// valid address. -static Name STACK_BASE("__stack_base"); -// The limit is the farthest it can grow to, which is the lowest valid address. -static Name STACK_LIMIT("__stack_limit"); // Exported function to set the base and the limit. static Name SET_STACK_LIMITS("__set_stack_limits"); @@ -60,18 +56,6 @@ static void addExportedFunction(Module& module, module.addExport(std::move(export_)); } -static void generateSetStackLimitFunctions(Module& module) { - Builder builder(module); - auto limitsFunc = builder.makeFunction( - SET_STACK_LIMITS, Signature({Type::i32, Type::i32}, Type::none), {}); - LocalGet* getBase = builder.makeLocalGet(0, Type::i32); - Expression* storeBase = builder.makeGlobalSet(STACK_BASE, getBase); - LocalGet* getLimit = builder.makeLocalGet(1, Type::i32); - Expression* storeLimit = builder.makeGlobalSet(STACK_LIMIT, getLimit); - limitsFunc->body = builder.makeBlock({storeBase, storeLimit}); - addExportedFunction(module, std::move(limitsFunc)); -} - struct EnforceStackLimits : public WalkerPass<PostWalker<EnforceStackLimits>> { EnforceStackLimits(const Global* stackPointer, const Global* stackBase, @@ -142,6 +126,10 @@ struct StackCheck : public Pass { return; } + // Pick appropriate names. + auto stackBaseName = Names::getValidGlobalName(*module, "__stack_base"); + auto stackLimitName = Names::getValidGlobalName(*module, "__stack_limit"); + Name handler; auto handlerName = runner->options.getArgumentOrDefault("stack-check-handler", ""); @@ -151,22 +139,33 @@ struct StackCheck : public Pass { } Builder builder(*module); - auto stackBase = builder.makeGlobal(STACK_BASE, - stackPointer->type, - builder.makeConst(int32_t(0)), - Builder::Mutable); - - auto stackLimit = builder.makeGlobal(STACK_LIMIT, - stackPointer->type, - builder.makeConst(int32_t(0)), - Builder::Mutable); + + // Add the globals. + auto stackBase = + module->addGlobal(builder.makeGlobal(stackBaseName, + stackPointer->type, + builder.makeConst(int32_t(0)), + Builder::Mutable)); + auto stackLimit = + module->addGlobal(builder.makeGlobal(stackLimitName, + stackPointer->type, + builder.makeConst(int32_t(0)), + Builder::Mutable)); + + // Instrument all the code. PassRunner innerRunner(module); - EnforceStackLimits( - stackPointer, stackBase.get(), stackLimit.get(), builder, handler) + EnforceStackLimits(stackPointer, stackBase, stackLimit, builder, handler) .run(&innerRunner, module); - module->addGlobal(std::move(stackBase)); - module->addGlobal(std::move(stackLimit)); - generateSetStackLimitFunctions(*module); + + // Generate the exported function. + auto limitsFunc = builder.makeFunction( + SET_STACK_LIMITS, Signature({Type::i32, Type::i32}, Type::none), {}); + auto* getBase = builder.makeLocalGet(0, Type::i32); + auto* storeBase = builder.makeGlobalSet(stackBaseName, getBase); + auto* getLimit = builder.makeLocalGet(1, Type::i32); + auto* storeLimit = builder.makeGlobalSet(stackLimitName, getLimit); + limitsFunc->body = builder.makeBlock({storeBase, storeLimit}); + addExportedFunction(*module, std::move(limitsFunc)); } }; diff --git a/test/passes/stack-check_enable-mutable-globals.txt b/test/passes/stack-check_enable-mutable-globals.txt index c89f112a8..3f8aa4da7 100644 --- a/test/passes/stack-check_enable-mutable-globals.txt +++ b/test/passes/stack-check_enable-mutable-globals.txt @@ -39,3 +39,25 @@ ) ) ) +(module + (type $i32_i32_=>_none (func (param i32 i32))) + (type $none_=>_i32 (func (result i32))) + (import "env" "__stack_pointer" (global $sp (mut i32))) + (global $__stack_base (mut i32) (i32.const 0)) + (global $__stack_limit (mut i32) (i32.const 0)) + (global $__stack_base_0 (mut i32) (i32.const 0)) + (global $__stack_limit_0 (mut i32) (i32.const 0)) + (export "use_stack" (func $0)) + (export "__set_stack_limits" (func $__set_stack_limits)) + (func $0 (result i32) + (unreachable) + ) + (func $__set_stack_limits (param $0 i32) (param $1 i32) + (global.set $__stack_base_0 + (local.get $0) + ) + (global.set $__stack_limit_0 + (local.get $1) + ) + ) +) diff --git a/test/passes/stack-check_enable-mutable-globals.wast b/test/passes/stack-check_enable-mutable-globals.wast index 3028039fd..c3583cd2c 100644 --- a/test/passes/stack-check_enable-mutable-globals.wast +++ b/test/passes/stack-check_enable-mutable-globals.wast @@ -5,3 +5,13 @@ (global.get $sp) ) ) +;; if the global names are taken we should not crash +(module + (import "env" "__stack_pointer" (global $sp (mut i32))) + (global $__stack_base (mut i32) (i32.const 0)) + (global $__stack_limit (mut i32) (i32.const 0)) + (export "use_stack" (func $0)) + (func $0 (result i32) + (unreachable) + ) +) |