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
}
}
// 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:
}
// 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:
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]
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]
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)
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
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)<<s-1
}
return 0 <= x
// x does not fit into int64
switch n := constant.BitLen(x); typ.kind {
case Uint, Uintptr:
- var s = uint(conf.sizeof(typ)) * 8
+ var s = uint(sizeof(typ)) * 8
return constant.Sign(x) >= 0 && n <= int(s)
case Uint64:
return constant.Sign(x) >= 0 && n <= 64
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
}
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) {
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
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
}
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:
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.
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
+ }
+ if a := f(T); a >= 1 {
+ return a
}
- return stdSizes.Alignof(T)
+ 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)
}
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]
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]
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)
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
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)<<s-1
}
return 0 <= x
// x does not fit into int64
switch n := constant.BitLen(x); typ.kind {
case Uint, Uintptr:
- var s = uint(conf.sizeof(typ)) * 8
+ var s = uint(sizeof(typ)) * 8
return constant.Sign(x) >= 0 && n <= int(s)
case Uint64:
return constant.Sign(x) >= 0 && n <= 64
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
}
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) {
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
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
}
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:
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.
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
+ }
+ if a := f(T); a >= 1 {
+ return a
}
- return stdSizes.Alignof(T)
+ 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)
}
_ = x[InvalidUnsafeSliceData-145]
_ = x[InvalidUnsafeString-146]
_ = x[InvalidClear-148]
+ _ = x[TypeTooLarge-149]
}
const (
_Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot"
_Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl"
_Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
- _Code_name_5 = "InvalidClear"
+ _Code_name_5 = "InvalidClearTypeTooLarge"
)
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 {
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) + ")"
}
// 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
)
--- /dev/null
+// 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" */ )
+}
--- /dev/null
+// 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" */ )
--- /dev/null
+// 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"
+}