Skip to content

Commit 98d55ab

Browse files
committed
compiler, runtime: make slice lookup panics recoverable
1 parent 88d273d commit 98d55ab

File tree

5 files changed

+19
-11
lines changed

5 files changed

+19
-11
lines changed

GNUmakefile

+2
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ TEST_PACKAGES_LINUX := \
383383
crypto/hmac \
384384
debug/dwarf \
385385
debug/plan9obj \
386+
encoding/binary \
386387
go/constant \
387388
image \
388389
io/ioutil \
@@ -406,6 +407,7 @@ TEST_PACKAGES_WINDOWS := \
406407
compress/flate \
407408
crypto/des \
408409
crypto/hmac \
410+
encoding/binary \
409411
go/constant \
410412
math/bits \
411413
strconv \

compiler/asserts.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value) {
3131

3232
// Now do the bounds check: index >= arrayLen
3333
outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "")
34-
b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", false)
34+
b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic", true)
3535
}
3636

3737
// createSliceBoundsCheck emits a bounds check before a slicing operation to make
@@ -230,7 +230,7 @@ func (b *builder) createDivideByZeroCheck(y llvm.Value) {
230230

231231
// createRuntimeAssert is a common function to create a new branch on an assert
232232
// bool, calling an assert func if the assert value is true (1).
233-
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, invoke bool) {
233+
func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string, isInvoke bool) {
234234
// Check whether we can resolve this check at compile time.
235235
if !assert.IsAConstantInt().IsNil() {
236236
val := assert.ZExtValue()
@@ -245,23 +245,17 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
245245
// current insert position.
246246
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
247247
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
248-
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
249248

250249
// Now branch to the out-of-bounds or the regular block.
251250
b.CreateCondBr(assert, faultBlock, nextBlock)
252251

253252
// Fail: the assert triggered so panic.
254253
b.SetInsertPointAtEnd(faultBlock)
255-
if invoke {
256-
// This runtime panic is recoverable.
257-
b.createRuntimeInvoke(assertFunc, nil, "")
258-
} else {
259-
// This runtime panic is not recoverable.
260-
b.createRuntimeCall(assertFunc, nil, "")
261-
}
254+
b.createRuntimeCallCommon(assertFunc, nil, "", isInvoke)
262255
b.CreateUnreachable()
263256

264257
// Ok: assert didn't trigger so continue normally.
258+
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
265259
b.SetInsertPointAtEnd(nextBlock)
266260
}
267261

src/runtime/error.go

+1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ func (r runtimeError) RuntimeError() {}
2121

2222
var (
2323
divideError error = runtimeError{"runtime error: integer divide by zero"}
24+
lookupError error = runtimeError{"runtime error: index out of range"}
2425
overflowError error = runtimeError{"runtime error: integer overflow"}
2526
)

src/runtime/panic.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func nilMapPanic() {
187187

188188
// Panic when trying to access an array or slice out of bounds.
189189
func lookupPanic() {
190-
runtimePanicAt(returnAddress(0), "index out of range")
190+
_panic(lookupError)
191191
}
192192

193193
// Panic when trying to slice a slice out of bounds.

testdata/recover.go

+11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func main() {
3232

3333
println("\n# runtime panics")
3434
runtimePanicDivByZero(1, 0)
35+
runtimePanicLookup([]int{1, 2, 3}, 10)
3536

3637
println("\n# runtime.Goexit")
3738
runtimeGoexit()
@@ -127,6 +128,16 @@ func runtimePanicDivByZero(a, b int) int {
127128
return a / b
128129
}
129130

131+
func runtimePanicLookup(slice []int, index int) int {
132+
defer func() {
133+
if err := recover(); err != nil {
134+
println("recovered:", err)
135+
}
136+
}()
137+
138+
return slice[index]
139+
}
140+
130141
func runtimeGoexit() {
131142
wg.Add(1)
132143
go func() {

0 commit comments

Comments
 (0)