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.
Этот коммит содержится в:
Ayke van Laethem 2024-02-27 14:18:47 +01:00 коммит произвёл Ron Evans
родитель 9951eb9990
коммит 1f6d34d995
3 изменённых файлов: 14 добавлений и 5 удалений

Просмотреть файл

@ -644,11 +644,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
case llvm.GetElementPtr: case llvm.GetElementPtr:
// GetElementPtr does pointer arithmetic, changing the offset of the // GetElementPtr does pointer arithmetic, changing the offset of the
// pointer into the underlying object. // pointer into the underlying object.
var offset uint64 var offset int64
for i := 1; i < len(operands); i += 2 { for i := 1; i < len(operands); i += 2 {
index := operands[i].Uint() index := operands[i].Int()
elementSize := operands[i+1].Uint() elementSize := operands[i+1].Int()
if int64(elementSize) < 0 { if elementSize < 0 {
// This is a struct field. // This is a struct field.
offset += index offset += index
} else { } else {
@ -662,7 +662,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err) return nil, mem, r.errorAt(inst, err)
} }
// GEP on fixed pointer value (for example, memory-mapped I/O). // 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)) locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
continue continue
} }

7
interp/testdata/basic.ll предоставленный
Просмотреть файл

@ -10,6 +10,8 @@ target triple = "x86_64--linux"
@main.exposedValue1 = global i16 0 @main.exposedValue1 = global i16 0
@main.exposedValue2 = global i16 0 @main.exposedValue2 = global i16 0
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer @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 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 %agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue 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 ret void
} }

2
interp/testdata/basic.out.ll предоставленный
Просмотреть файл

@ -9,6 +9,8 @@ target triple = "x86_64--linux"
@main.exposedValue1 = global i16 0 @main.exposedValue1 = global i16 0
@main.exposedValue2 = local_unnamed_addr global i16 0 @main.exposedValue2 = local_unnamed_addr global i16 0
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer @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 declare void @runtime.printint64(i64) unnamed_addr