compiler: fix MakeSlice bounds check and casting
Этот коммит содержится в:
родитель
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")
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче