aboutsummaryrefslogtreecommitdiffhomepage
path: root/interp
diff options
context:
space:
mode:
authorNia Waldvogel <[email protected]>2022-01-13 13:41:55 -0500
committerAyke <[email protected]>2022-01-21 14:49:36 +0100
commit2f57e4ff6dbbe176e065c104e2f419be2b21dd9f (patch)
treef469075764e7de2cabfcd59cec66569d420a4855 /interp
parent5e33dccf1ff2340a40d89b95f436554b8bc0e98c (diff)
downloadtinygo-2f57e4ff6dbbe176e065c104e2f419be2b21dd9f.tar.gz
tinygo-2f57e4ff6dbbe176e065c104e2f419be2b21dd9f.zip
interp: handle type assertions on nil interfaces
Previously, a type assertion on a nil interface would result in an out-of-bounds operand access, as we assumed it was a ptrtoint. This would usually result in an undefined value which happens not to have the same name as the asserted type (and therefore the assertion fails as expected). However, with an LLVM build with asserts, LLVM throws an assertion error: ``` interp.test: /home/niaow/go/src/github.com/tinygo-org/tinygo/llvm-project/llvm/include/llvm/IR/User.h:170: llvm::Value* llvm::User::getOperand(unsigned int) const: Assertion `i < NumUserOperands && "getOperand() out of range!"' failed. ``` This change handles a type code of 0 specially.
Diffstat (limited to 'interp')
-rw-r--r--interp/interpreter.go4
-rw-r--r--interp/testdata/interface.ll3
-rw-r--r--interp/testdata/interface.out.ll1
3 files changed, 8 insertions, 0 deletions
diff --git a/interp/interpreter.go b/interp/interpreter.go
index 64bb060d8..ece8b2579 100644
--- a/interp/interpreter.go
+++ b/interp/interpreter.go
@@ -388,6 +388,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
+ if !actualTypePtrToInt.IsAConstantInt().IsNil() && actualTypePtrToInt.ZExtValue() == 0 {
+ locals[inst.localIndex] = literalValue{uint8(0)}
+ break
+ }
actualType := actualTypePtrToInt.Operand(0)
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
locals[inst.localIndex] = literalValue{uint8(1)}
diff --git a/interp/testdata/interface.ll b/interp/testdata/interface.ll
index 060256d22..6520efc5c 100644
--- a/interp/testdata/interface.ll
+++ b/interp/testdata/interface.ll
@@ -5,6 +5,7 @@ target triple = "x86_64--linux"
%runtime.interfaceMethodInfo = type { i8*, i64 }
@main.v1 = global i1 0
[email protected] = global i1 0
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.typeid:named:main.foo" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@@ -23,5 +24,7 @@ entry:
; Test type asserts.
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
+ %typecode2 = call i1 @runtime.typeAssert(i64 0, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
+ store i1 %typecode2, i1* @main.v2
ret void
}
diff --git a/interp/testdata/interface.out.ll b/interp/testdata/interface.out.ll
index 2d2467b67..1fb9249be 100644
--- a/interp/testdata/interface.out.ll
+++ b/interp/testdata/interface.out.ll
@@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.v1 = local_unnamed_addr global i1 true
[email protected] = local_unnamed_addr global i1 false
define void @runtime.initAll() unnamed_addr {
entry: