mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/compile: don't panic if unsafe.Sizeof/Offsetof is used with oversize types
In the Sizes API, recognize an overflow (to a negative value) as a consequence of an oversize value, and specify as such in the API. Adjust the various size computations to take overflow into account. Recognize a negative size or offset as an error and report it rather than panicking. Use the same protocol for results provided by the default (StdSizes) and external Sizes implementations. Add a new error code TypeTooLarge for the new errors. Fixes #59190. Fixes #59207. Change-Id: I8c33a9e69932760275100112dde627289ac7695b Reviewed-on: https://go-review.googlesource.com/c/go/+/478919 Run-TryBot: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Robert Griesemer <gri@google.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
a0c9d153e0
commit
171850f169
@ -78,13 +78,23 @@ func isComplex(T types2.Type) bool {
|
|||||||
|
|
||||||
func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
|
func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
|
||||||
offsets := make([]int64, len(fields))
|
offsets := make([]int64, len(fields))
|
||||||
var o int64
|
var offs int64
|
||||||
for i, f := range fields {
|
for i, f := range fields {
|
||||||
|
if offs < 0 {
|
||||||
|
// all remaining offsets are too large
|
||||||
|
offsets[i] = -1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// offs >= 0
|
||||||
typ := f.Type()
|
typ := f.Type()
|
||||||
a := s.Alignof(typ)
|
a := s.Alignof(typ)
|
||||||
o = types.RoundUp(o, a)
|
offs = types.RoundUp(offs, a) // possibly < 0 if align overflows
|
||||||
offsets[i] = o
|
offsets[i] = offs
|
||||||
o += s.Sizeof(typ)
|
if d := s.Sizeof(typ); d >= 0 && offs >= 0 {
|
||||||
|
offs += d // ok to overflow to < 0
|
||||||
|
} else {
|
||||||
|
offs = -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return offsets
|
return offsets
|
||||||
}
|
}
|
||||||
@ -112,7 +122,20 @@ func (s *gcSizes) Sizeof(T types2.Type) int64 {
|
|||||||
}
|
}
|
||||||
// n > 0
|
// n > 0
|
||||||
// gc: Size includes alignment padding.
|
// 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:
|
case *types2.Slice:
|
||||||
return int64(types.PtrSize) * 3
|
return int64(types.PtrSize) * 3
|
||||||
case *types2.Struct:
|
case *types2.Struct:
|
||||||
@ -134,7 +157,7 @@ func (s *gcSizes) Sizeof(T types2.Type) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gc: Size includes alignment padding.
|
// 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:
|
case *types2.Interface:
|
||||||
return int64(types.PtrSize) * 2
|
return int64(types.PtrSize) * 2
|
||||||
case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
|
case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
|
||||||
|
@ -725,8 +725,13 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
|
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
offs := check.conf.offsetof(base, index)
|
||||||
|
if offs < 0 {
|
||||||
|
check.errorf(x, TypeTooLarge, "%s is too large", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
x.mode = constant_
|
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
|
// result is constant - no need to record signature
|
||||||
}
|
}
|
||||||
x.typ = Typ[Uintptr]
|
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))
|
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
size := check.conf.sizeof(x.typ)
|
||||||
|
if size < 0 {
|
||||||
|
check.errorf(x, TypeTooLarge, "%s is too large", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
x.mode = constant_
|
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
|
// result is constant - no need to record signature
|
||||||
}
|
}
|
||||||
x.typ = Typ[Uintptr]
|
x.typ = Typ[Uintptr]
|
||||||
|
@ -313,6 +313,12 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
conf = check.conf
|
conf = check.conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizeof := func(T Type) int64 {
|
||||||
|
s := conf.sizeof(T)
|
||||||
|
assert(s == 4 || s == 8)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isInteger(typ):
|
case isInteger(typ):
|
||||||
x := constant.ToInt(x)
|
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 {
|
if x, ok := constant.Int64Val(x); ok {
|
||||||
switch typ.kind {
|
switch typ.kind {
|
||||||
case Int:
|
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
|
return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
|
||||||
case Int8:
|
case Int8:
|
||||||
const s = 8
|
const s = 8
|
||||||
@ -339,7 +345,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
case Int64, UntypedInt:
|
case Int64, UntypedInt:
|
||||||
return true
|
return true
|
||||||
case Uint, Uintptr:
|
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 <= int64(1)<<s-1
|
||||||
}
|
}
|
||||||
return 0 <= x
|
return 0 <= x
|
||||||
@ -361,7 +367,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
// x does not fit into int64
|
// x does not fit into int64
|
||||||
switch n := constant.BitLen(x); typ.kind {
|
switch n := constant.BitLen(x); typ.kind {
|
||||||
case Uint, Uintptr:
|
case Uint, Uintptr:
|
||||||
var s = uint(conf.sizeof(typ)) * 8
|
var s = uint(sizeof(typ)) * 8
|
||||||
return constant.Sign(x) >= 0 && n <= int(s)
|
return constant.Sign(x) >= 0 && n <= int(s)
|
||||||
case Uint64:
|
case Uint64:
|
||||||
return constant.Sign(x) >= 0 && n <= 64
|
return constant.Sign(x) >= 0 && n <= 64
|
||||||
|
@ -10,14 +10,17 @@ package types2
|
|||||||
type Sizes interface {
|
type Sizes interface {
|
||||||
// Alignof returns the alignment of a variable of type T.
|
// Alignof returns the alignment of a variable of type T.
|
||||||
// Alignof must implement the alignment guarantees required by the spec.
|
// Alignof must implement the alignment guarantees required by the spec.
|
||||||
|
// The result must be >= 1.
|
||||||
Alignof(T Type) int64
|
Alignof(T Type) int64
|
||||||
|
|
||||||
// Offsetsof returns the offsets of the given struct fields, in bytes.
|
// Offsetsof returns the offsets of the given struct fields, in bytes.
|
||||||
// Offsetsof must implement the offset guarantees required by the spec.
|
// 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
|
Offsetsof(fields []*Var) []int64
|
||||||
|
|
||||||
// Sizeof returns the size of a variable of type T.
|
// Sizeof returns the size of a variable of type T.
|
||||||
// Sizeof must implement the size guarantees required by the spec.
|
// Sizeof must implement the size guarantees required by the spec.
|
||||||
|
// A negative result indicates that T is too large.
|
||||||
Sizeof(T Type) int64
|
Sizeof(T Type) int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +47,11 @@ type StdSizes struct {
|
|||||||
MaxAlign int64 // maximum alignment in bytes - must be >= 1
|
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
|
// For arrays and structs, alignment is defined in terms
|
||||||
// of alignment of the elements and fields, respectively.
|
// of alignment of the elements and fields, respectively.
|
||||||
switch t := under(T).(type) {
|
switch t := under(T).(type) {
|
||||||
@ -89,7 +96,7 @@ func (s *StdSizes) Alignof(T Type) int64 {
|
|||||||
case *TypeParam, *Union:
|
case *TypeParam, *Union:
|
||||||
unreachable()
|
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."
|
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
||||||
if a < 1 {
|
if a < 1 {
|
||||||
return 1
|
return 1
|
||||||
@ -118,12 +125,22 @@ func IsSyncAtomicAlign64(T Type) bool {
|
|||||||
|
|
||||||
func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
|
func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
|
||||||
offsets := make([]int64, len(fields))
|
offsets := make([]int64, len(fields))
|
||||||
var o int64
|
var offs int64
|
||||||
for i, f := range fields {
|
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)
|
a := s.Alignof(f.typ)
|
||||||
o = align(o, a)
|
offs = align(offs, a) // possibly < 0 if align overflows
|
||||||
offsets[i] = o
|
offsets[i] = offs
|
||||||
o += s.Sizeof(f.typ)
|
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 offsets
|
||||||
}
|
}
|
||||||
@ -163,9 +180,27 @@ func (s *StdSizes) Sizeof(T Type) int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
// n > 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)
|
a := s.Alignof(t.elem)
|
||||||
z := s.Sizeof(t.elem)
|
ea := align(esize, a) // possibly < 0 if align overflows
|
||||||
return align(z, a)*(n-1) + z
|
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:
|
case *Slice:
|
||||||
return s.WordSize * 3
|
return s.WordSize * 3
|
||||||
case *Struct:
|
case *Struct:
|
||||||
@ -174,7 +209,12 @@ func (s *StdSizes) Sizeof(T Type) int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
offsets := s.Offsetsof(t.fields)
|
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:
|
case *Interface:
|
||||||
// Type parameters lead to variable sizes/alignments;
|
// Type parameters lead to variable sizes/alignments;
|
||||||
// StdSizes.Sizeof won't be called for them.
|
// StdSizes.Sizeof won't be called for them.
|
||||||
@ -235,62 +275,69 @@ func SizesFor(compiler, arch string) Sizes {
|
|||||||
var stdSizes = SizesFor("gc", "amd64")
|
var stdSizes = SizesFor("gc", "amd64")
|
||||||
|
|
||||||
func (conf *Config) alignof(T Type) int64 {
|
func (conf *Config) alignof(T Type) int64 {
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Alignof
|
||||||
if a := s.Alignof(T); a >= 1 {
|
if conf.Sizes != nil {
|
||||||
return a
|
f = conf.Sizes.Alignof
|
||||||
}
|
|
||||||
panic("Config.Sizes.Alignof returned an alignment < 1")
|
|
||||||
}
|
}
|
||||||
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 {
|
func (conf *Config) offsetsof(T *Struct) []int64 {
|
||||||
var offsets []int64
|
var offsets []int64
|
||||||
if T.NumFields() > 0 {
|
if T.NumFields() > 0 {
|
||||||
// compute offsets on demand
|
// compute offsets on demand
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Offsetsof
|
||||||
offsets = s.Offsetsof(T.fields)
|
if conf.Sizes != nil {
|
||||||
// sanity checks
|
f = conf.Sizes.Offsetsof
|
||||||
if len(offsets) != T.NumFields() {
|
}
|
||||||
panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
|
offsets = f(T.fields)
|
||||||
}
|
// sanity checks
|
||||||
for _, o := range offsets {
|
if len(offsets) != T.NumFields() {
|
||||||
if o < 0 {
|
panic("implementation of offsetsof returned the wrong number of offsets")
|
||||||
panic("Config.Sizes.Offsetsof returned an offset < 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
offsets = stdSizes.Offsetsof(T.fields)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return offsets
|
return offsets
|
||||||
}
|
}
|
||||||
|
|
||||||
// offsetof returns the offset of the field specified via
|
// offsetof returns the offset of the field specified via
|
||||||
// the index sequence relative to typ. All embedded fields
|
// the index sequence relative to T. All embedded fields
|
||||||
// must be structs (rather than pointer to structs).
|
// must be structs (rather than pointers to structs).
|
||||||
func (conf *Config) offsetof(typ Type, index []int) int64 {
|
// If the offset is too large (because T is too large),
|
||||||
var o int64
|
// the result is negative.
|
||||||
|
func (conf *Config) offsetof(T Type, index []int) int64 {
|
||||||
|
var offs int64
|
||||||
for _, i := range index {
|
for _, i := range index {
|
||||||
s := under(typ).(*Struct)
|
s := under(T).(*Struct)
|
||||||
o += conf.offsetsof(s)[i]
|
d := conf.offsetsof(s)[i]
|
||||||
typ = s.fields[i].typ
|
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 {
|
func (conf *Config) sizeof(T Type) int64 {
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Sizeof
|
||||||
if z := s.Sizeof(T); z >= 0 {
|
if conf.Sizes != nil {
|
||||||
return z
|
f = conf.Sizes.Sizeof
|
||||||
}
|
|
||||||
panic("Config.Sizes.Sizeof returned a size < 0")
|
|
||||||
}
|
}
|
||||||
return stdSizes.Sizeof(T)
|
return f(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// align returns the smallest y >= x such that y % a == 0.
|
// 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 {
|
func align(x, a int64) int64 {
|
||||||
y := x + a - 1
|
assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0)
|
||||||
return y - y%a
|
return (x + a - 1) &^ (a - 1)
|
||||||
}
|
}
|
||||||
|
@ -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()))
|
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
offs := check.conf.offsetof(base, index)
|
||||||
|
if offs < 0 {
|
||||||
|
check.errorf(x, TypeTooLarge, "%s is too large", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
x.mode = constant_
|
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
|
// result is constant - no need to record signature
|
||||||
}
|
}
|
||||||
x.typ = Typ[Uintptr]
|
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))
|
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
size := check.conf.sizeof(x.typ)
|
||||||
|
if size < 0 {
|
||||||
|
check.errorf(x, TypeTooLarge, "%s is too large", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
x.mode = constant_
|
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
|
// result is constant - no need to record signature
|
||||||
}
|
}
|
||||||
x.typ = Typ[Uintptr]
|
x.typ = Typ[Uintptr]
|
||||||
|
@ -301,6 +301,12 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
conf = check.conf
|
conf = check.conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizeof := func(T Type) int64 {
|
||||||
|
s := conf.sizeof(T)
|
||||||
|
assert(s == 4 || s == 8)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isInteger(typ):
|
case isInteger(typ):
|
||||||
x := constant.ToInt(x)
|
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 {
|
if x, ok := constant.Int64Val(x); ok {
|
||||||
switch typ.kind {
|
switch typ.kind {
|
||||||
case Int:
|
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
|
return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
|
||||||
case Int8:
|
case Int8:
|
||||||
const s = 8
|
const s = 8
|
||||||
@ -327,7 +333,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
case Int64, UntypedInt:
|
case Int64, UntypedInt:
|
||||||
return true
|
return true
|
||||||
case Uint, Uintptr:
|
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 <= int64(1)<<s-1
|
||||||
}
|
}
|
||||||
return 0 <= x
|
return 0 <= x
|
||||||
@ -349,7 +355,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
|||||||
// x does not fit into int64
|
// x does not fit into int64
|
||||||
switch n := constant.BitLen(x); typ.kind {
|
switch n := constant.BitLen(x); typ.kind {
|
||||||
case Uint, Uintptr:
|
case Uint, Uintptr:
|
||||||
var s = uint(conf.sizeof(typ)) * 8
|
var s = uint(sizeof(typ)) * 8
|
||||||
return constant.Sign(x) >= 0 && n <= int(s)
|
return constant.Sign(x) >= 0 && n <= int(s)
|
||||||
case Uint64:
|
case Uint64:
|
||||||
return constant.Sign(x) >= 0 && n <= 64
|
return constant.Sign(x) >= 0 && n <= 64
|
||||||
|
@ -12,14 +12,17 @@ package types
|
|||||||
type Sizes interface {
|
type Sizes interface {
|
||||||
// Alignof returns the alignment of a variable of type T.
|
// Alignof returns the alignment of a variable of type T.
|
||||||
// Alignof must implement the alignment guarantees required by the spec.
|
// Alignof must implement the alignment guarantees required by the spec.
|
||||||
|
// The result must be >= 1.
|
||||||
Alignof(T Type) int64
|
Alignof(T Type) int64
|
||||||
|
|
||||||
// Offsetsof returns the offsets of the given struct fields, in bytes.
|
// Offsetsof returns the offsets of the given struct fields, in bytes.
|
||||||
// Offsetsof must implement the offset guarantees required by the spec.
|
// 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
|
Offsetsof(fields []*Var) []int64
|
||||||
|
|
||||||
// Sizeof returns the size of a variable of type T.
|
// Sizeof returns the size of a variable of type T.
|
||||||
// Sizeof must implement the size guarantees required by the spec.
|
// Sizeof must implement the size guarantees required by the spec.
|
||||||
|
// A negative result indicates that T is too large.
|
||||||
Sizeof(T Type) int64
|
Sizeof(T Type) int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +49,11 @@ type StdSizes struct {
|
|||||||
MaxAlign int64 // maximum alignment in bytes - must be >= 1
|
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
|
// For arrays and structs, alignment is defined in terms
|
||||||
// of alignment of the elements and fields, respectively.
|
// of alignment of the elements and fields, respectively.
|
||||||
switch t := under(T).(type) {
|
switch t := under(T).(type) {
|
||||||
@ -91,7 +98,7 @@ func (s *StdSizes) Alignof(T Type) int64 {
|
|||||||
case *TypeParam, *Union:
|
case *TypeParam, *Union:
|
||||||
unreachable()
|
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."
|
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
||||||
if a < 1 {
|
if a < 1 {
|
||||||
return 1
|
return 1
|
||||||
@ -120,12 +127,22 @@ func _IsSyncAtomicAlign64(T Type) bool {
|
|||||||
|
|
||||||
func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
|
func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
|
||||||
offsets := make([]int64, len(fields))
|
offsets := make([]int64, len(fields))
|
||||||
var o int64
|
var offs int64
|
||||||
for i, f := range fields {
|
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)
|
a := s.Alignof(f.typ)
|
||||||
o = align(o, a)
|
offs = align(offs, a) // possibly < 0 if align overflows
|
||||||
offsets[i] = o
|
offsets[i] = offs
|
||||||
o += s.Sizeof(f.typ)
|
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 offsets
|
||||||
}
|
}
|
||||||
@ -165,9 +182,27 @@ func (s *StdSizes) Sizeof(T Type) int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
// n > 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)
|
a := s.Alignof(t.elem)
|
||||||
z := s.Sizeof(t.elem)
|
ea := align(esize, a) // possibly < 0 if align overflows
|
||||||
return align(z, a)*(n-1) + z
|
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:
|
case *Slice:
|
||||||
return s.WordSize * 3
|
return s.WordSize * 3
|
||||||
case *Struct:
|
case *Struct:
|
||||||
@ -176,7 +211,12 @@ func (s *StdSizes) Sizeof(T Type) int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
offsets := s.Offsetsof(t.fields)
|
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:
|
case *Interface:
|
||||||
// Type parameters lead to variable sizes/alignments;
|
// Type parameters lead to variable sizes/alignments;
|
||||||
// StdSizes.Sizeof won't be called for them.
|
// StdSizes.Sizeof won't be called for them.
|
||||||
@ -237,62 +277,69 @@ func SizesFor(compiler, arch string) Sizes {
|
|||||||
var stdSizes = SizesFor("gc", "amd64")
|
var stdSizes = SizesFor("gc", "amd64")
|
||||||
|
|
||||||
func (conf *Config) alignof(T Type) int64 {
|
func (conf *Config) alignof(T Type) int64 {
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Alignof
|
||||||
if a := s.Alignof(T); a >= 1 {
|
if conf.Sizes != nil {
|
||||||
return a
|
f = conf.Sizes.Alignof
|
||||||
}
|
|
||||||
panic("Config.Sizes.Alignof returned an alignment < 1")
|
|
||||||
}
|
}
|
||||||
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 {
|
func (conf *Config) offsetsof(T *Struct) []int64 {
|
||||||
var offsets []int64
|
var offsets []int64
|
||||||
if T.NumFields() > 0 {
|
if T.NumFields() > 0 {
|
||||||
// compute offsets on demand
|
// compute offsets on demand
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Offsetsof
|
||||||
offsets = s.Offsetsof(T.fields)
|
if conf.Sizes != nil {
|
||||||
// sanity checks
|
f = conf.Sizes.Offsetsof
|
||||||
if len(offsets) != T.NumFields() {
|
}
|
||||||
panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
|
offsets = f(T.fields)
|
||||||
}
|
// sanity checks
|
||||||
for _, o := range offsets {
|
if len(offsets) != T.NumFields() {
|
||||||
if o < 0 {
|
panic("implementation of offsetsof returned the wrong number of offsets")
|
||||||
panic("Config.Sizes.Offsetsof returned an offset < 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
offsets = stdSizes.Offsetsof(T.fields)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return offsets
|
return offsets
|
||||||
}
|
}
|
||||||
|
|
||||||
// offsetof returns the offset of the field specified via
|
// offsetof returns the offset of the field specified via
|
||||||
// the index sequence relative to typ. All embedded fields
|
// the index sequence relative to T. All embedded fields
|
||||||
// must be structs (rather than pointer to structs).
|
// must be structs (rather than pointers to structs).
|
||||||
func (conf *Config) offsetof(typ Type, index []int) int64 {
|
// If the offset is too large (because T is too large),
|
||||||
var o int64
|
// the result is negative.
|
||||||
|
func (conf *Config) offsetof(T Type, index []int) int64 {
|
||||||
|
var offs int64
|
||||||
for _, i := range index {
|
for _, i := range index {
|
||||||
s := under(typ).(*Struct)
|
s := under(T).(*Struct)
|
||||||
o += conf.offsetsof(s)[i]
|
d := conf.offsetsof(s)[i]
|
||||||
typ = s.fields[i].typ
|
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 {
|
func (conf *Config) sizeof(T Type) int64 {
|
||||||
if s := conf.Sizes; s != nil {
|
f := stdSizes.Sizeof
|
||||||
if z := s.Sizeof(T); z >= 0 {
|
if conf.Sizes != nil {
|
||||||
return z
|
f = conf.Sizes.Sizeof
|
||||||
}
|
|
||||||
panic("Config.Sizes.Sizeof returned a size < 0")
|
|
||||||
}
|
}
|
||||||
return stdSizes.Sizeof(T)
|
return f(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// align returns the smallest y >= x such that y % a == 0.
|
// 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 {
|
func align(x, a int64) int64 {
|
||||||
y := x + a - 1
|
assert(x >= 0 && 1 <= a && a <= 8 && a&(a-1) == 0)
|
||||||
return y - y%a
|
return (x + a - 1) &^ (a - 1)
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,7 @@ func _() {
|
|||||||
_ = x[InvalidUnsafeSliceData-145]
|
_ = x[InvalidUnsafeSliceData-145]
|
||||||
_ = x[InvalidUnsafeString-146]
|
_ = x[InvalidUnsafeString-146]
|
||||||
_ = x[InvalidClear-148]
|
_ = x[InvalidClear-148]
|
||||||
|
_ = x[TypeTooLarge-149]
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -161,7 +162,7 @@ const (
|
|||||||
_Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot"
|
_Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot"
|
||||||
_Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl"
|
_Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl"
|
||||||
_Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
|
_Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
|
||||||
_Code_name_5 = "InvalidClear"
|
_Code_name_5 = "InvalidClearTypeTooLarge"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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_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_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_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 {
|
func (i Code) String() string {
|
||||||
@ -187,8 +189,9 @@ func (i Code) String() string {
|
|||||||
case 108 <= i && i <= 146:
|
case 108 <= i && i <= 146:
|
||||||
i -= 108
|
i -= 108
|
||||||
return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]]
|
return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]]
|
||||||
case i == 148:
|
case 148 <= i && i <= 149:
|
||||||
return _Code_name_5
|
i -= 148
|
||||||
|
return _Code_name_5[_Code_index_5[i]:_Code_index_5[i+1]]
|
||||||
default:
|
default:
|
||||||
return "Code(" + strconv.FormatInt(int64(i), 10) + ")"
|
return "Code(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
}
|
}
|
||||||
|
@ -1441,4 +1441,25 @@ const (
|
|||||||
// clear(x)
|
// clear(x)
|
||||||
// }
|
// }
|
||||||
InvalidClear
|
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
|
||||||
)
|
)
|
||||||
|
36
src/internal/types/testdata/fixedbugs/issue59190.go
vendored
Normal file
36
src/internal/types/testdata/fixedbugs/issue59190.go
vendored
Normal file
@ -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" */ )
|
||||||
|
}
|
12
src/internal/types/testdata/fixedbugs/issue59207.go
vendored
Normal file
12
src/internal/types/testdata/fixedbugs/issue59207.go
vendored
Normal file
@ -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" */ )
|
39
test/fixedbugs/issue59190.go
Normal file
39
test/fixedbugs/issue59190.go
Normal file
@ -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"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user