diff --git a/compiler/asserts.go b/compiler/asserts.go index e8e183d6..0affd81e 100644 --- a/compiler/asserts.go +++ b/compiler/asserts.go @@ -51,6 +51,11 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu // emitSliceBoundsCheck emits a bounds check before a slicing operation to make // sure it is within bounds. +// +// This function is both used for slicing a slice (low and high have their +// normal meaning) and for creating a new slice, where 'capacity' means the +// biggest possible slice capacity, 'low' means len and 'high' means cap. The +// logic is the same in both cases. func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.Value, lowType, highType *types.Basic) { if frame.fn.IsNoBounds() { // The //go:nobounds pragma was added to the function to avoid bounds diff --git a/compiler/compiler.go b/compiler/compiler.go index 5c4ad483..3ed910c5 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1772,37 +1772,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { } // Bounds checking. - if !frame.fn.IsNoBounds() { - checkFunc := "sliceBoundsCheckMake" - capacityType := c.uintptrType - capacityTypeWidth := capacityType.IntTypeWidth() - if sliceLen.Type().IntTypeWidth() > capacityTypeWidth || sliceCap.Type().IntTypeWidth() > capacityTypeWidth { - // System that is less than 64bit, meaning that the slice make - // params are bigger than uintptr. - checkFunc = "sliceBoundsCheckMake64" - capacityType = c.ctx.Int64Type() - capacityTypeWidth = capacityType.IntTypeWidth() - } - if sliceLen.Type().IntTypeWidth() < capacityTypeWidth { - if expr.Len.Type().(*types.Basic).Info()&types.IsUnsigned != 0 { - sliceLen = c.builder.CreateZExt(sliceLen, capacityType, "") - } else { - sliceLen = c.builder.CreateSExt(sliceLen, capacityType, "") - } - } - if sliceCap.Type().IntTypeWidth() < capacityTypeWidth { - if expr.Cap.Type().(*types.Basic).Info()&types.IsUnsigned != 0 { - sliceCap = c.builder.CreateZExt(sliceCap, capacityType, "") - } else { - sliceCap = c.builder.CreateSExt(sliceCap, capacityType, "") - } - } - maxSliceSize := maxSize - if elemSize != 0 { // avoid divide by zero - maxSliceSize = llvm.ConstSDiv(maxSize, llvm.ConstInt(c.uintptrType, elemSize, false)) - } - c.createRuntimeCall(checkFunc, []llvm.Value{sliceLen, sliceCap, maxSliceSize}, "") - } + c.emitSliceBoundsCheck(frame, maxSize, sliceLen, sliceCap, expr.Len.Type().(*types.Basic), expr.Cap.Type().(*types.Basic)) // Allocate the backing array. // TODO: escape analysis @@ -1814,9 +1784,15 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { slicePtr := c.createRuntimeCall("alloc", []llvm.Value{sliceSize}, "makeslice.buf") slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array") - if c.targetData.TypeAllocSize(sliceLen.Type()) > c.targetData.TypeAllocSize(c.uintptrType) { - sliceLen = c.builder.CreateTrunc(sliceLen, c.uintptrType, "") - sliceCap = c.builder.CreateTrunc(sliceCap, c.uintptrType, "") + // Extend or truncate if necessary. This is safe as we've already done + // the bounds check. + sliceLen, err = c.parseConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos()) + if err != nil { + return llvm.Value{}, err + } + sliceCap, err = c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) + if err != nil { + return llvm.Value{}, err } // Create the slice. diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 16bb75d7..8bf80d86 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -49,17 +49,3 @@ func lookuppanic() { func slicepanic() { runtimePanic("slice out of range") } - -// Check for bounds in *ssa.MakeSlice. -func sliceBoundsCheckMake(length, capacity uintptr, max uintptr) { - if length > capacity || capacity > max { - runtimePanic("slice size out of range") - } -} - -// Check for bounds in *ssa.MakeSlice. Supports 64-bit indexes. -func sliceBoundsCheckMake64(length, capacity uint64, max uintptr) { - if length > capacity || capacity > uint64(max) { - runtimePanic("slice size out of range") - } -}