diff --git a/src/cmd/compile/internal/noder/sizes.go b/src/cmd/compile/internal/noder/sizes.go index 107f4d0adf..dff8d7bb9a 100644 --- a/src/cmd/compile/internal/noder/sizes.go +++ b/src/cmd/compile/internal/noder/sizes.go @@ -78,13 +78,23 @@ func isComplex(T types2.Type) bool { func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 { offsets := make([]int64, len(fields)) - var o int64 + var offs int64 for i, f := range fields { + if offs < 0 { + // all remaining offsets are too large + offsets[i] = -1 + continue + } + // offs >= 0 typ := f.Type() a := s.Alignof(typ) - o = types.RoundUp(o, a) - offsets[i] = o - o += s.Sizeof(typ) + offs = types.RoundUp(offs, a) // possibly < 0 if align overflows + offsets[i] = offs + if d := s.Sizeof(typ); d >= 0 && offs >= 0 { + offs += d // ok to overflow to < 0 + } else { + offs = -1 + } } return offsets } @@ -112,7 +122,20 @@ func (s *gcSizes) Sizeof(T types2.Type) int64 { } // n > 0 // gc: Size includes alignment padding. - return s.Sizeof(t.Elem()) * n + esize := s.Sizeof(t.Elem()) + if esize < 0 { + return -1 // array element too large + } + if esize == 0 { + return 0 // 0-size element + } + // esize > 0 + // Final size is esize * n; and size must be <= maxInt64. + const maxInt64 = 1<<63 - 1 + if esize > maxInt64/n { + return -1 // esize * n overflows + } + return esize * n case *types2.Slice: return int64(types.PtrSize) * 3 case *types2.Struct: @@ -134,7 +157,7 @@ func (s *gcSizes) Sizeof(T types2.Type) int64 { } // gc: Size includes alignment padding. - return types.RoundUp(offsets[n-1]+last, s.Alignof(t)) + return types.RoundUp(offsets[n-1]+last, s.Alignof(t)) // may overflow to < 0 which is ok case *types2.Interface: return int64(types.PtrSize) * 2 case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature: diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 4e4d756652..94fddca19a 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -725,8 +725,13 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type())) } } else { + offs := check.conf.offsetof(base, index) + if offs < 0 { + check.errorf(x, TypeTooLarge, "%s is too large", x) + return + } x.mode = constant_ - x.val = constant.MakeInt64(check.conf.offsetof(base, index)) + x.val = constant.MakeInt64(offs) // result is constant - no need to record signature } x.typ = Typ[Uintptr] @@ -744,8 +749,13 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) } } else { + size := check.conf.sizeof(x.typ) + if size < 0 { + check.errorf(x, TypeTooLarge, "%s is too large", x) + return + } x.mode = constant_ - x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + x.val = constant.MakeInt64(size) // result is constant - no need to record signature } x.typ = Typ[Uintptr] diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 72c0186339..1217d2fc7e 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -313,6 +313,12 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c conf = check.conf } + sizeof := func(T Type) int64 { + s := conf.sizeof(T) + assert(s == 4 || s == 8) + return s + } + switch { case isInteger(typ): x := constant.ToInt(x) @@ -325,7 +331,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c if x, ok := constant.Int64Val(x); ok { switch typ.kind { case Int: - var s = uint(conf.sizeof(typ)) * 8 + var s = uint(sizeof(typ)) * 8 return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 case Int8: const s = 8 @@ -339,7 +345,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c case Int64, UntypedInt: return true case Uint, Uintptr: - if s := uint(conf.sizeof(typ)) * 8; s < 64 { + if s := uint(sizeof(typ)) * 8; s < 64 { return 0 <= x && x <= int64(1)<= 0 && n <= int(s) case Uint64: return constant.Sign(x) >= 0 && n <= 64 diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go index c99a12b2e9..59f600a05b 100644 --- a/src/cmd/compile/internal/types2/sizes.go +++ b/src/cmd/compile/internal/types2/sizes.go @@ -10,14 +10,17 @@ package types2 type Sizes interface { // Alignof returns the alignment of a variable of type T. // Alignof must implement the alignment guarantees required by the spec. + // The result must be >= 1. Alignof(T Type) int64 // Offsetsof returns the offsets of the given struct fields, in bytes. // Offsetsof must implement the offset guarantees required by the spec. + // A negative entry in the result indicates that the struct is too large. Offsetsof(fields []*Var) []int64 // Sizeof returns the size of a variable of type T. // Sizeof must implement the size guarantees required by the spec. + // A negative result indicates that T is too large. Sizeof(T Type) int64 } @@ -44,7 +47,11 @@ type StdSizes struct { MaxAlign int64 // maximum alignment in bytes - must be >= 1 } -func (s *StdSizes) Alignof(T Type) int64 { +func (s *StdSizes) Alignof(T Type) (result int64) { + defer func() { + assert(result >= 1) + }() + // For arrays and structs, alignment is defined in terms // of alignment of the elements and fields, respectively. switch t := under(T).(type) { @@ -89,7 +96,7 @@ func (s *StdSizes) Alignof(T Type) int64 { case *TypeParam, *Union: unreachable() } - a := s.Sizeof(T) // may be 0 + a := s.Sizeof(T) // may be 0 or negative // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." if a < 1 { return 1 @@ -118,12 +125,22 @@ func IsSyncAtomicAlign64(T Type) bool { func (s *StdSizes) Offsetsof(fields []*Var) []int64 { offsets := make([]int64, len(fields)) - var o int64 + var offs int64 for i, f := range fields { + if offs < 0 { + // all remaining offsets are too large + offsets[i] = -1 + continue + } + // offs >= 0 a := s.Alignof(f.typ) - o = align(o, a) - offsets[i] = o - o += s.Sizeof(f.typ) + offs = align(offs, a) // possibly < 0 if align overflows + offsets[i] = offs + if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 { + offs += d // ok to overflow to < 0 + } else { + offs = -1 // f.typ or offs is too large + } } return offsets } @@ -163,9 +180,27 @@ func (s *StdSizes) Sizeof(T Type) int64 { return 0 } // n > 0 + esize := s.Sizeof(t.elem) + if esize < 0 { + return -1 // element too large + } + if esize == 0 { + return 0 // 0-size element + } + // esize > 0 a := s.Alignof(t.elem) - z := s.Sizeof(t.elem) - return align(z, a)*(n-1) + z + ea := align(esize, a) // possibly < 0 if align overflows + if ea < 0 { + return -1 + } + // ea >= 1 + n1 := n - 1 // n1 >= 0 + // Final size is ea*n1 + esize; and size must be <= maxInt64. + const maxInt64 = 1<<63 - 1 + if n1 > 0 && ea > maxInt64/n1 { + return -1 // ea*n1 overflows + } + return ea*n1 + esize // may still overflow to < 0 which is ok case *Slice: return s.WordSize * 3 case *Struct: @@ -174,7 +209,12 @@ func (s *StdSizes) Sizeof(T Type) int64 { return 0 } offsets := s.Offsetsof(t.fields) - return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) + offs := offsets[n-1] + size := s.Sizeof(t.fields[n-1].typ) + if offs < 0 || size < 0 { + return -1 // type too large + } + return offs + size // may overflow to < 0 which is ok case *Interface: // Type parameters lead to variable sizes/alignments; // StdSizes.Sizeof won't be called for them. @@ -235,62 +275,69 @@ func SizesFor(compiler, arch string) Sizes { var stdSizes = SizesFor("gc", "amd64") func (conf *Config) alignof(T Type) int64 { - if s := conf.Sizes; s != nil { - if a := s.Alignof(T); a >= 1 { - return a - } - panic("Config.Sizes.Alignof returned an alignment < 1") + f := stdSizes.Alignof + if conf.Sizes != nil { + f = conf.Sizes.Alignof } - return stdSizes.Alignof(T) + if a := f(T); a >= 1 { + return a + } + panic("implementation of alignof returned an alignment < 1") } func (conf *Config) offsetsof(T *Struct) []int64 { var offsets []int64 if T.NumFields() > 0 { // compute offsets on demand - if s := conf.Sizes; s != nil { - offsets = s.Offsetsof(T.fields) - // sanity checks - if len(offsets) != T.NumFields() { - panic("Config.Sizes.Offsetsof returned the wrong number of offsets") - } - for _, o := range offsets { - if o < 0 { - panic("Config.Sizes.Offsetsof returned an offset < 0") - } - } - } else { - offsets = stdSizes.Offsetsof(T.fields) + f := stdSizes.Offsetsof + if conf.Sizes != nil { + f = conf.Sizes.Offsetsof + } + offsets = f(T.fields) + // sanity checks + if len(offsets) != T.NumFields() { + panic("implementation of offsetsof returned the wrong number of offsets") } } return offsets } // offsetof returns the offset of the field specified via -// the index sequence relative to typ. All embedded fields -// must be structs (rather than pointer to structs). -func (conf *Config) offsetof(typ Type, index []int) int64 { - var o int64 +// the index sequence relative to T. All embedded fields +// must be structs (rather than pointers to structs). +// If the offset is too large (because T is too large), +// the result is negative. +func (conf *Config) offsetof(T Type, index []int) int64 { + var offs int64 for _, i := range index { - s := under(typ).(*Struct) - o += conf.offsetsof(s)[i] - typ = s.fields[i].typ + s := under(T).(*Struct) + d := conf.offsetsof(s)[i] + if d < 0 { + return -1 + } + offs += d + if offs < 0 { + return -1 + } + T = s.fields[i].typ } - return o + return offs } +// sizeof returns the size of T. +// If T is too large, the result is negative. func (conf *Config) sizeof(T Type) int64 { - if s := conf.Sizes; s != nil { - if z := s.Sizeof(T); z >= 0 { - return z - } - panic("Config.Sizes.Sizeof returned a size < 0") + f := stdSizes.Sizeof + if conf.Sizes != nil { + f = conf.Sizes.Sizeof } - return stdSizes.Sizeof(T) + return f(T) } // align returns the smallest y >= x such that y % a == 0. +// a must be within 1 and 8 and it must be a power of 2. +// The result may be negative due to overflow. func align(x, a int64) int64 { - y := x + a - 1 - return y - y%a + assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0) + return (x + a - 1) &^ (a - 1) } diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 0783f921eb..783e00090b 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -726,8 +726,13 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type())) } } else { + offs := check.conf.offsetof(base, index) + if offs < 0 { + check.errorf(x, TypeTooLarge, "%s is too large", x) + return + } x.mode = constant_ - x.val = constant.MakeInt64(check.conf.offsetof(base, index)) + x.val = constant.MakeInt64(offs) // result is constant - no need to record signature } x.typ = Typ[Uintptr] @@ -745,8 +750,13 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) } } else { + size := check.conf.sizeof(x.typ) + if size < 0 { + check.errorf(x, TypeTooLarge, "%s is too large", x) + return + } x.mode = constant_ - x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + x.val = constant.MakeInt64(size) // result is constant - no need to record signature } x.typ = Typ[Uintptr] diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 4dff5332ea..3a4b30d2f2 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -301,6 +301,12 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c conf = check.conf } + sizeof := func(T Type) int64 { + s := conf.sizeof(T) + assert(s == 4 || s == 8) + return s + } + switch { case isInteger(typ): x := constant.ToInt(x) @@ -313,7 +319,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c if x, ok := constant.Int64Val(x); ok { switch typ.kind { case Int: - var s = uint(conf.sizeof(typ)) * 8 + var s = uint(sizeof(typ)) * 8 return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 case Int8: const s = 8 @@ -327,7 +333,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c case Int64, UntypedInt: return true case Uint, Uintptr: - if s := uint(conf.sizeof(typ)) * 8; s < 64 { + if s := uint(sizeof(typ)) * 8; s < 64 { return 0 <= x && x <= int64(1)<= 0 && n <= int(s) case Uint64: return constant.Sign(x) >= 0 && n <= 64 diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index d32866913e..2dcaebe402 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -12,14 +12,17 @@ package types type Sizes interface { // Alignof returns the alignment of a variable of type T. // Alignof must implement the alignment guarantees required by the spec. + // The result must be >= 1. Alignof(T Type) int64 // Offsetsof returns the offsets of the given struct fields, in bytes. // Offsetsof must implement the offset guarantees required by the spec. + // A negative entry in the result indicates that the struct is too large. Offsetsof(fields []*Var) []int64 // Sizeof returns the size of a variable of type T. // Sizeof must implement the size guarantees required by the spec. + // A negative result indicates that T is too large. Sizeof(T Type) int64 } @@ -46,7 +49,11 @@ type StdSizes struct { MaxAlign int64 // maximum alignment in bytes - must be >= 1 } -func (s *StdSizes) Alignof(T Type) int64 { +func (s *StdSizes) Alignof(T Type) (result int64) { + defer func() { + assert(result >= 1) + }() + // For arrays and structs, alignment is defined in terms // of alignment of the elements and fields, respectively. switch t := under(T).(type) { @@ -91,7 +98,7 @@ func (s *StdSizes) Alignof(T Type) int64 { case *TypeParam, *Union: unreachable() } - a := s.Sizeof(T) // may be 0 + a := s.Sizeof(T) // may be 0 or negative // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." if a < 1 { return 1 @@ -120,12 +127,22 @@ func _IsSyncAtomicAlign64(T Type) bool { func (s *StdSizes) Offsetsof(fields []*Var) []int64 { offsets := make([]int64, len(fields)) - var o int64 + var offs int64 for i, f := range fields { + if offs < 0 { + // all remaining offsets are too large + offsets[i] = -1 + continue + } + // offs >= 0 a := s.Alignof(f.typ) - o = align(o, a) - offsets[i] = o - o += s.Sizeof(f.typ) + offs = align(offs, a) // possibly < 0 if align overflows + offsets[i] = offs + if d := s.Sizeof(f.typ); d >= 0 && offs >= 0 { + offs += d // ok to overflow to < 0 + } else { + offs = -1 // f.typ or offs is too large + } } return offsets } @@ -165,9 +182,27 @@ func (s *StdSizes) Sizeof(T Type) int64 { return 0 } // n > 0 + esize := s.Sizeof(t.elem) + if esize < 0 { + return -1 // element too large + } + if esize == 0 { + return 0 // 0-size element + } + // esize > 0 a := s.Alignof(t.elem) - z := s.Sizeof(t.elem) - return align(z, a)*(n-1) + z + ea := align(esize, a) // possibly < 0 if align overflows + if ea < 0 { + return -1 + } + // ea >= 1 + n1 := n - 1 // n1 >= 0 + // Final size is ea*n1 + esize; and size must be <= maxInt64. + const maxInt64 = 1<<63 - 1 + if n1 > 0 && ea > maxInt64/n1 { + return -1 // ea*n1 overflows + } + return ea*n1 + esize // may still overflow to < 0 which is ok case *Slice: return s.WordSize * 3 case *Struct: @@ -176,7 +211,12 @@ func (s *StdSizes) Sizeof(T Type) int64 { return 0 } offsets := s.Offsetsof(t.fields) - return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) + offs := offsets[n-1] + size := s.Sizeof(t.fields[n-1].typ) + if offs < 0 || size < 0 { + return -1 // type too large + } + return offs + size // may overflow to < 0 which is ok case *Interface: // Type parameters lead to variable sizes/alignments; // StdSizes.Sizeof won't be called for them. @@ -237,62 +277,69 @@ func SizesFor(compiler, arch string) Sizes { var stdSizes = SizesFor("gc", "amd64") func (conf *Config) alignof(T Type) int64 { - if s := conf.Sizes; s != nil { - if a := s.Alignof(T); a >= 1 { - return a - } - panic("Config.Sizes.Alignof returned an alignment < 1") + f := stdSizes.Alignof + if conf.Sizes != nil { + f = conf.Sizes.Alignof } - return stdSizes.Alignof(T) + if a := f(T); a >= 1 { + return a + } + panic("implementation of alignof returned an alignment < 1") } func (conf *Config) offsetsof(T *Struct) []int64 { var offsets []int64 if T.NumFields() > 0 { // compute offsets on demand - if s := conf.Sizes; s != nil { - offsets = s.Offsetsof(T.fields) - // sanity checks - if len(offsets) != T.NumFields() { - panic("Config.Sizes.Offsetsof returned the wrong number of offsets") - } - for _, o := range offsets { - if o < 0 { - panic("Config.Sizes.Offsetsof returned an offset < 0") - } - } - } else { - offsets = stdSizes.Offsetsof(T.fields) + f := stdSizes.Offsetsof + if conf.Sizes != nil { + f = conf.Sizes.Offsetsof + } + offsets = f(T.fields) + // sanity checks + if len(offsets) != T.NumFields() { + panic("implementation of offsetsof returned the wrong number of offsets") } } return offsets } // offsetof returns the offset of the field specified via -// the index sequence relative to typ. All embedded fields -// must be structs (rather than pointer to structs). -func (conf *Config) offsetof(typ Type, index []int) int64 { - var o int64 +// the index sequence relative to T. All embedded fields +// must be structs (rather than pointers to structs). +// If the offset is too large (because T is too large), +// the result is negative. +func (conf *Config) offsetof(T Type, index []int) int64 { + var offs int64 for _, i := range index { - s := under(typ).(*Struct) - o += conf.offsetsof(s)[i] - typ = s.fields[i].typ + s := under(T).(*Struct) + d := conf.offsetsof(s)[i] + if d < 0 { + return -1 + } + offs += d + if offs < 0 { + return -1 + } + T = s.fields[i].typ } - return o + return offs } +// sizeof returns the size of T. +// If T is too large, the result is negative. func (conf *Config) sizeof(T Type) int64 { - if s := conf.Sizes; s != nil { - if z := s.Sizeof(T); z >= 0 { - return z - } - panic("Config.Sizes.Sizeof returned a size < 0") + f := stdSizes.Sizeof + if conf.Sizes != nil { + f = conf.Sizes.Sizeof } - return stdSizes.Sizeof(T) + return f(T) } // align returns the smallest y >= x such that y % a == 0. +// a must be within 1 and 8 and it must be a power of 2. +// The result may be negative due to overflow. func align(x, a int64) int64 { - y := x + a - 1 - return y - y%a + assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0) + return (x + a - 1) &^ (a - 1) } diff --git a/src/internal/types/errors/code_string.go b/src/internal/types/errors/code_string.go index 303cc3b388..d00e62bf1d 100644 --- a/src/internal/types/errors/code_string.go +++ b/src/internal/types/errors/code_string.go @@ -153,6 +153,7 @@ func _() { _ = x[InvalidUnsafeSliceData-145] _ = x[InvalidUnsafeString-146] _ = x[InvalidClear-148] + _ = x[TypeTooLarge-149] } const ( @@ -161,7 +162,7 @@ const ( _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot" _Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl" _Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" - _Code_name_5 = "InvalidClear" + _Code_name_5 = "InvalidClearTypeTooLarge" ) var ( @@ -169,6 +170,7 @@ var ( _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756} _Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354} _Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603} + _Code_index_5 = [...]uint8{0, 12, 24} ) func (i Code) String() string { @@ -187,8 +189,9 @@ func (i Code) String() string { case 108 <= i && i <= 146: i -= 108 return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]] - case i == 148: - return _Code_name_5 + case 148 <= i && i <= 149: + i -= 148 + return _Code_name_5[_Code_index_5[i]:_Code_index_5[i+1]] default: return "Code(" + strconv.FormatInt(int64(i), 10) + ")" } diff --git a/src/internal/types/errors/codes.go b/src/internal/types/errors/codes.go index db7a4252c1..0982aeb397 100644 --- a/src/internal/types/errors/codes.go +++ b/src/internal/types/errors/codes.go @@ -1441,4 +1441,25 @@ const ( // clear(x) // } InvalidClear + + // TypeTooLarge occurs if unsafe.Sizeof or unsafe.Offsetof is + // called with an expression whose type is too large. + // + // Example: + // import "unsafe" + // + // type E [1 << 31 - 1]int + // var a [1 << 31]E + // var _ = unsafe.Sizeof(a) + // + // Example: + // import "unsafe" + // + // type E [1 << 31 - 1]int + // var s struct { + // _ [1 << 31]E + // x int + // } + // var _ = unsafe.Offsetof(s.x) + TypeTooLarge ) diff --git a/src/internal/types/testdata/fixedbugs/issue59190.go b/src/internal/types/testdata/fixedbugs/issue59190.go new file mode 100644 index 0000000000..fd08303303 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue59190.go @@ -0,0 +1,36 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import "unsafe" + +type E [1 << 30]complex128 +var a [1 << 30]E +var _ = unsafe.Sizeof(a /* ERROR "too large" */ ) + +var s struct { + _ [1 << 30]E + x int +} +var _ = unsafe.Offsetof(s /* ERROR "too large" */ .x) + +// Test case from issue (modified so it also triggers on 32-bit platforms). + +type A [1]int +type S struct { + x A + y [1 << 30]A + z [1 << 30]struct{} +} +type T [1 << 30][1 << 30]S + +func _() { + var a A + var s S + var t T + _ = unsafe.Sizeof(a) + _ = unsafe.Sizeof(s) + _ = unsafe.Sizeof(t /* ERROR "too large" */ ) +} diff --git a/src/internal/types/testdata/fixedbugs/issue59207.go b/src/internal/types/testdata/fixedbugs/issue59207.go new file mode 100644 index 0000000000..59b36e243d --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue59207.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import "unsafe" + +type E [1 << 32]byte + +var a [1 << 32]E // size of a must not overflow to 0 +var _ = unsafe.Sizeof(a /* ERROR "too large" */ ) diff --git a/test/fixedbugs/issue59190.go b/test/fixedbugs/issue59190.go new file mode 100644 index 0000000000..48273eaaa2 --- /dev/null +++ b/test/fixedbugs/issue59190.go @@ -0,0 +1,39 @@ +// errorcheck + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import "unsafe" + +type E [1 << 30]complex128 + +var a [1 << 30]E +var _ = unsafe.Sizeof(a) // ERROR "too large" + +var s struct { + _ [1 << 30]E + x int +} +var _ = unsafe.Offsetof(s.x) // ERROR "too large" + +// Test case from issue (modified so it also triggers on 32-bit platforms). + +type A [1]int +type S struct { + x A + y [1 << 30]A + z [1 << 30]struct{} +} +type T [1 << 30][1 << 30]S + +func _() { + var a A + var s S + var t T + _ = unsafe.Sizeof(a) + _ = unsafe.Sizeof(s) + _ = unsafe.Sizeof(t) // ERROR "too large" +}