Skip to content

Commit 80d9411

Browse files
aykevldeadprogram
authored andcommitted
interp: improve error handling of markExternal* functions
1 parent 9de76fb commit 80d9411

File tree

3 files changed

+53
-20
lines changed

3 files changed

+53
-20
lines changed

interp/interp.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ func Run(mod llvm.Module, debug bool) error {
121121
r.builder.CreateCall(fn, []llvm.Value{i8undef}, "")
122122
// Make sure that any globals touched by the package
123123
// initializer, won't be accessed by later package initializers.
124-
r.markExternalLoad(fn)
124+
err := r.markExternalLoad(fn)
125+
if err != nil {
126+
return fmt.Errorf("failed to interpret package %s: %w", r.pkgName, err)
127+
}
125128
continue
126129
}
127130
return callErr
@@ -288,12 +291,16 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function {
288291
// variable. Another package initializer might read from the same global
289292
// variable. By marking this function as being run at runtime, that load
290293
// instruction will need to be run at runtime instead of at compile time.
291-
func (r *runner) markExternalLoad(llvmValue llvm.Value) {
294+
func (r *runner) markExternalLoad(llvmValue llvm.Value) error {
292295
mem := memoryView{r: r}
293-
mem.markExternalLoad(llvmValue)
296+
err := mem.markExternalLoad(llvmValue)
297+
if err != nil {
298+
return err
299+
}
294300
for index, obj := range mem.objects {
295301
if obj.marked > r.objects[index].marked {
296302
r.objects[index].marked = obj.marked
297303
}
298304
}
305+
return nil
299306
}

interp/interpreter.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,18 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
945945
args := operands[:len(operands)-1]
946946
for _, arg := range args {
947947
if arg.Type().TypeKind() == llvm.PointerTypeKind {
948-
mem.markExternalStore(arg)
948+
err := mem.markExternalStore(arg)
949+
if err != nil {
950+
return r.errorAt(inst, err)
951+
}
949952
}
950953
}
951954
result = r.builder.CreateCall(llvmFn, args, inst.name)
952955
case llvm.Load:
953-
mem.markExternalLoad(operands[0])
956+
err := mem.markExternalLoad(operands[0])
957+
if err != nil {
958+
return r.errorAt(inst, err)
959+
}
954960
result = r.builder.CreateLoad(operands[0], inst.name)
955961
if inst.llvmInst.IsVolatile() {
956962
result.SetVolatile(true)
@@ -959,7 +965,10 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
959965
result.SetOrdering(ordering)
960966
}
961967
case llvm.Store:
962-
mem.markExternalStore(operands[1])
968+
err := mem.markExternalStore(operands[1])
969+
if err != nil {
970+
return r.errorAt(inst, err)
971+
}
963972
result = r.builder.CreateStore(operands[0], operands[1])
964973
if inst.llvmInst.IsVolatile() {
965974
result.SetVolatile(true)

interp/memory.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package interp
1717
import (
1818
"encoding/binary"
1919
"errors"
20+
"fmt"
2021
"math"
2122
"math/big"
2223
"strconv"
@@ -104,28 +105,28 @@ func (mv *memoryView) revert() {
104105
// means that the interpreter can still read from it, but cannot write to it as
105106
// that would mean the external read (done at runtime) reads from a state that
106107
// would not exist had the whole initialization been done at runtime.
107-
func (mv *memoryView) markExternalLoad(llvmValue llvm.Value) {
108-
mv.markExternal(llvmValue, 1)
108+
func (mv *memoryView) markExternalLoad(llvmValue llvm.Value) error {
109+
return mv.markExternal(llvmValue, 1)
109110
}
110111

111112
// markExternalStore marks the given LLVM value as having an external write.
112113
// This means that the interpreter can no longer read from it or write to it, as
113114
// that would happen in a different order than if all initialization were
114115
// happening at runtime.
115-
func (mv *memoryView) markExternalStore(llvmValue llvm.Value) {
116-
mv.markExternal(llvmValue, 2)
116+
func (mv *memoryView) markExternalStore(llvmValue llvm.Value) error {
117+
return mv.markExternal(llvmValue, 2)
117118
}
118119

119120
// markExternal is a helper for markExternalLoad and markExternalStore, and
120121
// should not be called directly.
121-
func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) {
122+
func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) error {
122123
if llvmValue.IsUndef() || llvmValue.IsNull() {
123124
// Null and undef definitely don't contain (valid) pointers.
124-
return
125+
return nil
125126
}
126127
if !llvmValue.IsAInstruction().IsNil() || !llvmValue.IsAArgument().IsNil() {
127128
// These are considered external by default, there is nothing to mark.
128-
return
129+
return nil
129130
}
130131

131132
if !llvmValue.IsAGlobalValue().IsNil() {
@@ -144,7 +145,10 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) {
144145
// Using mark '2' (which means read/write access) because
145146
// even from an object that is only read from, the resulting
146147
// loaded pointer can be written to.
147-
mv.markExternal(initializer, 2)
148+
err := mv.markExternal(initializer, 2)
149+
if err != nil {
150+
return err
151+
}
148152
}
149153
} else {
150154
// This is a function. Go through all instructions and mark all
@@ -170,7 +174,10 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) {
170174
for i := 0; i < numOperands; i++ {
171175
// Using mark '2' (which means read/write access)
172176
// because this might be a store instruction.
173-
mv.markExternal(inst.Operand(i), 2)
177+
err := mv.markExternal(inst.Operand(i), 2)
178+
if err != nil {
179+
return err
180+
}
174181
}
175182
}
176183
}
@@ -179,9 +186,12 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) {
179186
} else if !llvmValue.IsAConstantExpr().IsNil() {
180187
switch llvmValue.Opcode() {
181188
case llvm.IntToPtr, llvm.PtrToInt, llvm.BitCast, llvm.GetElementPtr:
182-
mv.markExternal(llvmValue.Operand(0), mark)
189+
err := mv.markExternal(llvmValue.Operand(0), mark)
190+
if err != nil {
191+
return err
192+
}
183193
default:
184-
panic("interp: unknown constant expression")
194+
return fmt.Errorf("interp: unknown constant expression '%s'", instructionNameMap[llvmValue.Opcode()])
185195
}
186196
} else if !llvmValue.IsAInlineAsm().IsNil() {
187197
// Inline assembly can modify globals but only exported globals. Let's
@@ -196,18 +206,25 @@ func (mv *memoryView) markExternal(llvmValue llvm.Value, mark uint8) {
196206
numElements := llvmType.StructElementTypesCount()
197207
for i := 0; i < numElements; i++ {
198208
element := llvm.ConstExtractValue(llvmValue, []uint32{uint32(i)})
199-
mv.markExternal(element, mark)
209+
err := mv.markExternal(element, mark)
210+
if err != nil {
211+
return err
212+
}
200213
}
201214
case llvm.ArrayTypeKind:
202215
numElements := llvmType.ArrayLength()
203216
for i := 0; i < numElements; i++ {
204217
element := llvm.ConstExtractValue(llvmValue, []uint32{uint32(i)})
205-
mv.markExternal(element, mark)
218+
err := mv.markExternal(element, mark)
219+
if err != nil {
220+
return err
221+
}
206222
}
207223
default:
208-
panic("interp: unknown type kind in markExternalValue")
224+
return errors.New("interp: unknown type kind in markExternalValue")
209225
}
210226
}
227+
return nil
211228
}
212229

213230
// hasExternalLoadOrStore returns true if this object has an external load or

0 commit comments

Comments
 (0)