@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
// This version is independent of the TinyGo version number.
const Version = 15 // last change: add crypto assembly aliases
const Version = 16 // last change: fix max slice size
func init ( ) {
func init ( ) {
llvm . InitializeAllTargets ( )
llvm . InitializeAllTargets ( )
@ -1439,6 +1439,28 @@ func (b *builder) getValue(expr ssa.Value) llvm.Value {
}
}
}
}
// maxSliceSize determines the maximum size a slice of the given element type
// can be.
func ( c * compilerContext ) maxSliceSize ( elementType llvm . Type ) uint64 {
// Calculate ^uintptr(0), which is the max value that fits in uintptr.
maxPointerValue := llvm . ConstNot ( llvm . ConstInt ( c . uintptrType , 0 , false ) ) . ZExtValue ( )
// Calculate (^uint(0))/2, which is the max value that fits in an int.
maxIntegerValue := llvm . ConstNot ( llvm . ConstInt ( c . intType , 0 , false ) ) . ZExtValue ( ) / 2
// Determine the maximum allowed size for a slice. The biggest possible
// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
// divide by the element type to get the real maximum size.
maxSize := maxPointerValue / c . targetData . TypeAllocSize ( elementType )
// len(slice) is an int. Make sure the length remains small enough to fit in
// an int.
if maxSize > maxIntegerValue {
maxSize = maxIntegerValue
}
return maxSize
}
// createExpr translates a Go SSA expression to LLVM IR. This can be zero, one,
// createExpr translates a Go SSA expression to LLVM IR. This can be zero, one,
// or multiple LLVM IR instructions and/or runtime calls.
// or multiple LLVM IR instructions and/or runtime calls.
func ( b * builder ) createExpr ( expr ssa . Value ) ( llvm . Value , error ) {
func ( b * builder ) createExpr ( expr ssa . Value ) ( llvm . Value , error ) {
@ -1652,10 +1674,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
elemSize := b . targetData . TypeAllocSize ( llvmElemType )
elemSize := b . targetData . TypeAllocSize ( llvmElemType )
elemSizeValue := llvm . ConstInt ( b . uintptrType , elemSize , false )
elemSizeValue := llvm . ConstInt ( b . uintptrType , elemSize , false )
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in
maxSize := b . maxSliceSize ( llvmElemType )
// uintptr if uintptr were signed.
if elemSize > maxSize {
maxSize := llvm . ConstLShr ( llvm . ConstNot ( llvm . ConstInt ( b . uintptrType , 0 , false ) ) , llvm . ConstInt ( b . uintptrType , 1 , false ) )
if elemSize > maxSize . ZExtValue ( ) {
// This seems to be checked by the typechecker already, but let's
// This seems to be checked by the typechecker already, but let's
// check it again just to be sure.
// check it again just to be sure.
return llvm . Value { } , b . makeError ( expr . Pos ( ) , fmt . Sprintf ( "slice element type is too big (%v bytes)" , elemSize ) )
return llvm . Value { } , b . makeError ( expr . Pos ( ) , fmt . Sprintf ( "slice element type is too big (%v bytes)" , elemSize ) )
@ -1664,7 +1684,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
// Bounds checking.
// Bounds checking.
lenType := expr . Len . Type ( ) . Underlying ( ) . ( * types . Basic )
lenType := expr . Len . Type ( ) . Underlying ( ) . ( * types . Basic )
capType := expr . Cap . Type ( ) . Underlying ( ) . ( * types . Basic )
capType := expr . Cap . Type ( ) . Underlying ( ) . ( * types . Basic )
b . createSliceBoundsCheck ( maxSize , sliceLen , sliceCap , sliceCap , lenType , capType , capType )
maxSizeValue := llvm . ConstInt ( b . uintptrType , maxSize , false )
b . createSliceBoundsCheck ( maxSizeValue , sliceLen , sliceCap , sliceCap , lenType , capType , capType )
// Allocate the backing array.
// Allocate the backing array.
sliceCapCast , err := b . createConvert ( expr . Cap . Type ( ) , types . Typ [ types . Uintptr ] , sliceCap , expr . Pos ( ) )
sliceCapCast , err := b . createConvert ( expr . Cap . Type ( ) , types . Typ [ types . Uintptr ] , sliceCap , expr . Pos ( ) )