summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsumu Takikawa <asumu@igalia.com>2021-12-15 16:24:32 -0800
committerGitHub <noreply@github.com>2021-12-15 16:24:32 -0800
commit5718b65c381cbed697712a87886fcbb0c3db36a8 (patch)
tree5deb7bee07dfd551b85ec7363eb8711e742d4305
parentb3f1efb261b059d40a4d103c803ccbe3c32df7ae (diff)
downloadwabt-5718b65c381cbed697712a87886fcbb0c3db36a8.tar.gz
wabt-5718b65c381cbed697712a87886fcbb0c3db36a8.tar.bz2
wabt-5718b65c381cbed697712a87886fcbb0c3db36a8.zip
interpreter: Fix infinite looping on `return_call` (#1762)
The code offset fixup for the target of a `return_call` was not being done properly due to invalid initialization of the offset value, and due to the fixup location being put at the wrong offset in the instruction stream. Fixes issue #1761
-rw-r--r--src/interp/binary-reader-interp.cc7
-rw-r--r--test/interp/return-call-set-local.txt20
2 files changed, 25 insertions, 2 deletions
diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc
index 7a1bc26e..699fdd20 100644
--- a/src/interp/binary-reader-interp.cc
+++ b/src/interp/binary-reader-interp.cc
@@ -576,7 +576,7 @@ Result BinaryReaderInterp::OnFunctionCount(Index count) {
Result BinaryReaderInterp::OnFunction(Index index, Index sig_index) {
CHECK_RESULT(validator_.OnFunction(GetLocation(), Var(sig_index)));
FuncType& func_type = module_.func_types[sig_index];
- module_.funcs.push_back(FuncDesc{func_type, {}, 0, {}});
+ module_.funcs.push_back(FuncDesc{func_type, {}, Istream::kInvalidOffset, {}});
func_types_.push_back(func_type);
return Result::Ok;
}
@@ -1132,7 +1132,10 @@ Result BinaryReaderInterp::OnReturnCallExpr(Index func_index) {
if (func_index >= num_func_imports()) {
istream_.Emit(Opcode::InterpAdjustFrameForReturnCall, func_index);
- istream_.Emit(Opcode::Br, GetFuncOffset(func_index));
+ istream_.Emit(Opcode::Br);
+ // We emit this separately to ensure that the fixup generated by
+ // GetFuncOffset comes after the Br opcode.
+ istream_.Emit(GetFuncOffset(func_index));
} else {
istream_.Emit(Opcode::InterpCallImport, func_index);
istream_.Emit(Opcode::Return);
diff --git a/test/interp/return-call-set-local.txt b/test/interp/return-call-set-local.txt
new file mode 100644
index 00000000..5b566361
--- /dev/null
+++ b/test/interp/return-call-set-local.txt
@@ -0,0 +1,20 @@
+;;; TOOL: run-interp
+;;; ARGS*: --enable-tail-call
+(module
+ (func (export "f") (result i32)
+ (i64.const 1)
+ (return_call $g))
+
+ (func $g (param i64) (result i32)
+ (i32.const 3)
+ (return_call $h))
+
+ (func $h (param i32) (result i32)
+ (i32.const 2)
+ (local.set 0)
+ (local.get 0)
+ return)
+)
+(;; STDOUT ;;;
+f() => i32:2
+;;; STDOUT ;;)