summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/PostEmscripten.cpp38
-rw-r--r--test/passes/post-emscripten.txt17
-rw-r--r--test/passes/post-emscripten.wast15
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)
)