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
|
// emitSliceBoundsCheck emits a bounds check before a slicing operation to make
|
||||||
// sure it is within bounds.
|
// 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) {
|
func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.Value, lowType, highType *types.Basic) {
|
||||||
if frame.fn.IsNoBounds() {
|
if frame.fn.IsNoBounds() {
|
||||||
// The //go:nobounds pragma was added to the function to avoid bounds
|
// 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.
|
// Bounds checking.
|
||||||
if !frame.fn.IsNoBounds() {
|
c.emitSliceBoundsCheck(frame, maxSize, sliceLen, sliceCap, expr.Len.Type().(*types.Basic), expr.Cap.Type().(*types.Basic))
|
||||||
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}, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the backing array.
|
// Allocate the backing array.
|
||||||
// TODO: escape analysis
|
// 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.createRuntimeCall("alloc", []llvm.Value{sliceSize}, "makeslice.buf")
|
||||||
slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
|
slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
|
||||||
|
|
||||||
if c.targetData.TypeAllocSize(sliceLen.Type()) > c.targetData.TypeAllocSize(c.uintptrType) {
|
// Extend or truncate if necessary. This is safe as we've already done
|
||||||
sliceLen = c.builder.CreateTrunc(sliceLen, c.uintptrType, "")
|
// the bounds check.
|
||||||
sliceCap = c.builder.CreateTrunc(sliceCap, c.uintptrType, "")
|
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.
|
// Create the slice.
|
||||||
|
|
|
@ -49,17 +49,3 @@ func lookuppanic() {
|
||||||
func slicepanic() {
|
func slicepanic() {
|
||||||
runtimePanic("slice out of range")
|
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче