From 1f6d34d995a0c77117b63c3e287549322d3c5d1f Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 27 Feb 2024 14:18:47 +0100 Subject: [PATCH] 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. --- interp/interpreter.go | 10 +++++----- interp/testdata/basic.ll | 7 +++++++ interp/testdata/basic.out.ll | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/interp/interpreter.go b/interp/interpreter.go index 864d6f65..605f4d8f 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 6d1d010f..0275dcbb 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 +@main.gepArray = global [8 x i8] zeroinitializer +@main.negativeGEP = 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 342d4965..2685850e 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 +@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer +@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2) declare void @runtime.printint64(i64) unnamed_addr