compiler: fix MakeSlice bounds check and casting

Этот коммит содержится в:
Ayke van Laethem 2019-04-05 16:55:34 +02:00 коммит произвёл Ron Evans
родитель 3a76a49ddf
коммит 6a2a587dff
3 изменённых файлов: 15 добавлений и 48 удалений

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

@ -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

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

@ -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.

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

@ -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")
}
}