aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2024-02-27 14:18:47 +0100
committerRon Evans <[email protected]>2024-02-27 15:16:38 +0100
commit1f6d34d995a0c77117b63c3e287549322d3c5d1f (patch)
treebb8f390833488fce22f26213bf20e18204493915
parent9951eb9990071aaf5e29665cc3185c1abe7368dc (diff)
downloadtinygo-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.go10
-rw-r--r--interp/testdata/basic.ll7
-rw-r--r--interp/testdata/basic.out.ll2
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