diff options
author | Ayke van Laethem <[email protected]> | 2024-02-27 14:18:47 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2024-02-27 15:16:38 +0100 |
commit | 1f6d34d995a0c77117b63c3e287549322d3c5d1f (patch) | |
tree | bb8f390833488fce22f26213bf20e18204493915 | |
parent | 9951eb9990071aaf5e29665cc3185c1abe7368dc (diff) | |
download | tinygo-1f6d34d995a0c77117b63c3e287549322d3c5d1f.tar.gz tinygo-1f6d34d995a0c77117b63c3e287549322d3c5d1f.zip |
interp: make getelementptr offsets signed
getelementptr offsets are signed, not unsigned. Yet they were used as
unsigned integers in interp.
Somehow this worked most of the time, until finally there was some code
that did a getelementptr with a negative index.
-rw-r--r-- | interp/interpreter.go | 10 | ||||
-rw-r--r-- | interp/testdata/basic.ll | 7 | ||||
-rw-r--r-- | interp/testdata/basic.out.ll | 2 |
3 files changed, 14 insertions, 5 deletions
diff --git a/interp/interpreter.go b/interp/interpreter.go index 864d6f652..605f4d8fc 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -644,11 +644,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent case llvm.GetElementPtr: // GetElementPtr does pointer arithmetic, changing the offset of the // pointer into the underlying object. - var offset uint64 + var offset int64 for i := 1; i < len(operands); i += 2 { - index := operands[i].Uint() - elementSize := operands[i+1].Uint() - if int64(elementSize) < 0 { + index := operands[i].Int() + elementSize := operands[i+1].Int() + if elementSize < 0 { // This is a struct field. offset += index } else { @@ -662,7 +662,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent return nil, mem, r.errorAt(inst, err) } // GEP on fixed pointer value (for example, memory-mapped I/O). - ptrValue := operands[0].Uint() + offset + ptrValue := operands[0].Uint() + uint64(offset) locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8)) continue } diff --git a/interp/testdata/basic.ll b/interp/testdata/basic.ll index 6d1d010f4..0275dcbb6 100644 --- a/interp/testdata/basic.ll +++ b/interp/testdata/basic.ll @@ -10,6 +10,8 @@ target triple = "x86_64--linux" @main.exposedValue1 = global i16 0 @main.exposedValue2 = global i16 0 @main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer [email protected] = global [8 x i8] zeroinitializer [email protected] = global ptr null declare void @runtime.printint64(i64) unnamed_addr @@ -88,6 +90,11 @@ entry: %agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0 store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue + ; negative GEP instruction + %ngep1 = getelementptr [8 x i8], ptr @main.negativeGEP, i32 0, i32 5 + %ngep2 = getelementptr [8 x i8], ptr %ngep1, i32 0, i32 -3 + store ptr %ngep2, ptr @main.negativeGEP + ret void } diff --git a/interp/testdata/basic.out.ll b/interp/testdata/basic.out.ll index 342d4965f..2685850eb 100644 --- a/interp/testdata/basic.out.ll +++ b/interp/testdata/basic.out.ll @@ -9,6 +9,8 @@ target triple = "x86_64--linux" @main.exposedValue1 = global i16 0 @main.exposedValue2 = local_unnamed_addr global i16 0 @main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer [email protected] = local_unnamed_addr global [8 x i8] zeroinitializer [email protected] = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2) declare void @runtime.printint64(i64) unnamed_addr |