compiler, runtime: make slice lookup panics recoverable

This commit is contained in:
Ayke van Laethem
2025-02-26 12:38:06 +01:00
parent 88d273da97
commit 98d55ab070
5 changed files with 19 additions and 11 deletions
+2
View File
@@ -383,6 +383,7 @@ TEST_PACKAGES_LINUX := \
crypto/hmac \ crypto/hmac \
debug/dwarf \ debug/dwarf \
debug/plan9obj \ debug/plan9obj \
encoding/binary \
go/constant \ go/constant \
image \ image \
io/ioutil \ io/ioutil \
@@ -406,6 +407,7 @@ TEST_PACKAGES_WINDOWS := \
compress/flate \ compress/flate \
crypto/des \ crypto/des \
crypto/hmac \ crypto/hmac \
encoding/binary \
go/constant \ go/constant \
math/bits \ math/bits \
strconv \ strconv \
+4 -10
View File
@@ -31,7 +31,7 @@ func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value) {
// Now do the bounds check: index >= arrayLen // Now do the bounds check: index >= arrayLen
outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "") outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "")
b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", false) b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", true)
} }
// createSliceBoundsCheck emits a bounds check before a slicing operation to make // createSliceBoundsCheck emits a bounds check before a slicing operation to make
@@ -230,7 +230,7 @@ func (b *builder) createDivideByZeroCheck(y llvm.Value) {
// createRuntimeAssert is a common function to create a new branch on an assert // createRuntimeAssert is a common function to create a new branch on an assert
// bool, calling an assert func if the assert value is true (1). // bool, calling an assert func if the assert value is true (1).
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, invoke bool) { func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, isInvoke bool) {
// Check whether we can resolve this check at compile time. // Check whether we can resolve this check at compile time.
if !assert.IsAConstantInt().IsNil() { if !assert.IsAConstantInt().IsNil() {
val := assert.ZExtValue() val := assert.ZExtValue()
@@ -245,23 +245,17 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
// current insert position. // current insert position.
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw") faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
nextBlock := b.insertBasicBlock(blockPrefix + ".next") nextBlock := b.insertBasicBlock(blockPrefix + ".next")
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block. // Now branch to the out-of-bounds or the regular block.
b.CreateCondBr(assert, faultBlock, nextBlock) b.CreateCondBr(assert, faultBlock, nextBlock)
// Fail: the assert triggered so panic. // Fail: the assert triggered so panic.
b.SetInsertPointAtEnd(faultBlock) b.SetInsertPointAtEnd(faultBlock)
if invoke { b.createRuntimeCallCommon(assertFunc, nil, "", isInvoke)
// This runtime panic is recoverable.
b.createRuntimeInvoke(assertFunc, nil, "")
} else {
// This runtime panic is not recoverable.
b.createRuntimeCall(assertFunc, nil, "")
}
b.CreateUnreachable() b.CreateUnreachable()
// Ok: assert didn't trigger so continue normally. // Ok: assert didn't trigger so continue normally.
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
b.SetInsertPointAtEnd(nextBlock) b.SetInsertPointAtEnd(nextBlock)
} }
+1
View File
@@ -21,5 +21,6 @@ func (r runtimeError) RuntimeError() {}
var ( var (
divideError error = runtimeError{"runtime error: integer divide by zero"} divideError error = runtimeError{"runtime error: integer divide by zero"}
lookupError error = runtimeError{"runtime error: index out of range"}
overflowError error = runtimeError{"runtime error: integer overflow"} overflowError error = runtimeError{"runtime error: integer overflow"}
) )
+1 -1
View File
@@ -187,7 +187,7 @@ func nilMapPanic() {
// Panic when trying to access an array or slice out of bounds. // Panic when trying to access an array or slice out of bounds.
func lookupPanic() { func lookupPanic() {
runtimePanicAt(returnAddress(0), "index out of range") _panic(lookupError)
} }
// Panic when trying to slice a slice out of bounds. // Panic when trying to slice a slice out of bounds.
+11
View File
@@ -32,6 +32,7 @@ func main() {
println("\n# runtime panics") println("\n# runtime panics")
runtimePanicDivByZero(1, 0) runtimePanicDivByZero(1, 0)
runtimePanicLookup([]int{1, 2, 3}, 10)
println("\n# runtime.Goexit") println("\n# runtime.Goexit")
runtimeGoexit() runtimeGoexit()
@@ -127,6 +128,16 @@ func runtimePanicDivByZero(a, b int) int {
return a / b return a / b
} }
func runtimePanicLookup(slice []int, index int) int {
defer func() {
if err := recover(); err != nil {
println("recovered:", err)
}
}()
return slice[index]
}
func runtimeGoexit() { func runtimeGoexit() {
wg.Add(1) wg.Add(1)
go func() { go func() {