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 {
|
||||
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:
|
||||
|
@ -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]
|
||||
|
@ -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)<<s-1
|
||||
}
|
||||
return 0 <= x
|
||||
@ -361,7 +367,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
||||
// 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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)<<s-1
|
||||
}
|
||||
return 0 <= x
|
||||
@ -349,7 +355,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c
|
||||
// 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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) + ")"
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
|
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