diff options
author | Ayke van Laethem <[email protected]> | 2021-10-14 15:55:50 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-11-02 22:16:15 +0100 |
commit | 27cbb5353811bf50043b9616d530593108172be5 (patch) | |
tree | 2ac960a9188062dd213fc0a71b302df0109616a9 /interp | |
parent | 0704794def59aa78b4735124cebeef59713f40b4 (diff) | |
download | tinygo-27cbb5353811bf50043b9616d530593108172be5.tar.gz tinygo-27cbb5353811bf50043b9616d530593108172be5.zip |
interp: support const getelementptr with non-zero first offset
This is uncommon, but it does happen if the source pointer is a bitcast
of a global. For example, if a struct is cast to an i8*, it's possible
to index beyond what would appear to be the size of the pointer (i8*).
Diffstat (limited to 'interp')
-rw-r--r-- | interp/memory.go | 5 | ||||
-rw-r--r-- | interp/testdata/consteval.ll | 8 | ||||
-rw-r--r-- | interp/testdata/consteval.out.ll | 2 |
3 files changed, 11 insertions, 4 deletions
diff --git a/interp/memory.go b/interp/memory.go index 53b798a3e..c7024091b 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -985,12 +985,9 @@ func (v *rawValue) set(llvmValue llvm.Value, r *runner) { case llvm.GetElementPtr: ptr := llvmValue.Operand(0) index := llvmValue.Operand(1) - if checks && index.IsAConstantInt().IsNil() || index.ZExtValue() != 0 { - panic("expected first index of const gep to be i32 0") - } numOperands := llvmValue.OperandsCount() elementType := ptr.Type().ElementType() - totalOffset := uint64(0) + totalOffset := r.targetData.TypeAllocSize(elementType) * index.ZExtValue() for i := 2; i < numOperands; i++ { indexValue := llvmValue.Operand(i) if checks && indexValue.IsAConstantInt().IsNil() { diff --git a/interp/testdata/consteval.ll b/interp/testdata/consteval.ll index b3f664dee..9afb9ff7e 100644 --- a/interp/testdata/consteval.ll +++ b/interp/testdata/consteval.ll @@ -3,6 +3,8 @@ target triple = "x86_64--linux" @intToPtrResult = global i8 0 @ptrToIntResult = global i8 0 +@someArray = internal global {i16, i8, i8} zeroinitializer +@someArrayPointer = global i8* zeroinitializer define void @runtime.initAll() { call void @main.init() @@ -12,6 +14,7 @@ define void @runtime.initAll() { define internal void @main.init() { call void @testIntToPtr() call void @testPtrToInt() + call void @testConstGEP() ret void } @@ -40,3 +43,8 @@ b: store i8 2, i8* @ptrToIntResult ret void } + +define internal void @testConstGEP() { + store i8* getelementptr inbounds (i8, i8* bitcast ({i16, i8, i8}* @someArray to i8*), i32 2), i8** @someArrayPointer + ret void +} diff --git a/interp/testdata/consteval.out.ll b/interp/testdata/consteval.out.ll index 175babbf7..5fac449e4 100644 --- a/interp/testdata/consteval.out.ll +++ b/interp/testdata/consteval.out.ll @@ -3,6 +3,8 @@ target triple = "x86_64--linux" @intToPtrResult = local_unnamed_addr global i8 2 @ptrToIntResult = local_unnamed_addr global i8 2 +@someArray = internal global { i16, i8, i8 } zeroinitializer +@someArrayPointer = local_unnamed_addr global i8* getelementptr inbounds ({ i16, i8, i8 }, { i16, i8, i8 }* @someArray, i64 0, i32 1) define void @runtime.initAll() local_unnamed_addr { ret void |