diff options
-rw-r--r-- | src/passes/PostEmscripten.cpp | 38 | ||||
-rw-r--r-- | test/passes/post-emscripten.txt | 17 | ||||
-rw-r--r-- | test/passes/post-emscripten.wast | 15 |
3 files changed, 50 insertions, 20 deletions
diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index 403fb998b..f3ad35783 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -108,20 +108,32 @@ struct PostEmscripten : public Pass { void visitCall(Call* curr) { auto* target = getModule()->getFunction(curr->target); - if (isInvoke(target)) { - // The first operand is the function pointer index, which must be - // constant if we are to optimize it statically. - if (auto* index = curr->operands[0]->dynCast<Const>()) { - auto actualTarget = flatTable.names.at(index->value.geti32()); - if (!map[getModule()->getFunction(actualTarget)].canThrow) { - // This invoke cannot throw! Make it a direct call. - curr->target = actualTarget; - for (Index i = 0; i < curr->operands.size() - 1; i++) { - curr->operands[i] = curr->operands[i + 1]; - } - curr->operands.resize(curr->operands.size() - 1); - } + if (!isInvoke(target)) { + return; + } + // The first operand is the function pointer index, which must be + // constant if we are to optimize it statically. + if (auto* index = curr->operands[0]->dynCast<Const>()) { + size_t indexValue = index->value.geti32(); + if (indexValue >= flatTable.names.size()) { + // UB can lead to indirect calls to invalid pointers. + return; + } + auto actualTarget = flatTable.names[indexValue]; + if (actualTarget.isNull()) { + // UB can lead to an indirect call of 0 or an index in which there + // is no function name. + return; + } + if (map[getModule()->getFunction(actualTarget)].canThrow) { + return; + } + // This invoke cannot throw! Make it a direct call. + curr->target = actualTarget; + for (Index i = 0; i < curr->operands.size() - 1; i++) { + curr->operands[i] = curr->operands[i + 1]; } + curr->operands.resize(curr->operands.size() - 1); } } }; diff --git a/test/passes/post-emscripten.txt b/test/passes/post-emscripten.txt index 36f8a4dab..5acb7e355 100644 --- a/test/passes/post-emscripten.txt +++ b/test/passes/post-emscripten.txt @@ -1,14 +1,11 @@ (module (type $i32_f32_=>_none (func (param i32 f32))) - (type $none_=>_none (func)) (type $i32_i32_f32_=>_none (func (param i32 i32 f32))) + (type $none_=>_none (func)) (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32))) (memory $0 256 256) (table $0 7 7 funcref) - (elem (i32.const 0) $f1 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe) - (func $f1 - (nop) - ) + (elem (i32.const 1) $exc $other_safe $other_unsafe $deep_safe $deep_unsafe) (func $exc (call $other_safe (i32.const 42) @@ -34,6 +31,16 @@ (i32.const 42) (f32.const 3.141590118408203) ) + (call $invoke_vif + (i32.const 0) + (i32.const 42) + (f32.const 3.141590118408203) + ) + (call $invoke_vif + (i32.const 1337) + (i32.const 42) + (f32.const 3.141590118408203) + ) ) (func $other_safe (param $0 i32) (param $1 f32) (nop) diff --git a/test/passes/post-emscripten.wast b/test/passes/post-emscripten.wast index 99fa3b57b..3c3eb6cdd 100644 --- a/test/passes/post-emscripten.wast +++ b/test/passes/post-emscripten.wast @@ -3,8 +3,7 @@ (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32))) (memory 256 256) (table 7 7 funcref) - (elem (i32.const 0) $f1 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe) - (func $f1) + (elem (i32.const 1) $exc $other_safe $other_unsafe $deep_safe $deep_unsafe) (func $exc (call $invoke_vif (i32.const 2) ;; other_safe() @@ -31,6 +30,18 @@ (i32.const 42) (f32.const 3.14159) ) + ;; there is no function at index 0, so this cannot be optimized + (call $invoke_vif + (i32.const 0) + (i32.const 42) + (f32.const 3.14159) + ) + ;; there is no function at index 1337, so this cannot be optimized + (call $invoke_vif + (i32.const 1337) + (i32.const 42) + (f32.const 3.14159) + ) ) (func $other_safe (param i32) (param f32) ) |