aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2022-06-14 14:38:56 -0700
committerKeith Randall <khr@golang.org>2022-06-14 23:23:04 +0000
commitc22a6c3b906cd37616d76da5f504c4c3e5677d94 (patch)
treef29f68155340cebebadc2909e52129f7d9474c84 /src
parente1e66a03a6bb3210034b640923fa253d7def1a26 (diff)
downloadgo-c22a6c3b906cd37616d76da5f504c4c3e5677d94.tar.xz
reflect: when StructOf overflows computing size/offset, panic
Fixes #52740 Change-Id: I849e585deb77cfcfc1b517be4a171eb29b30c5f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/412214 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Keith Randall <khr@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/reflect/all_test.go81
-rw-r--r--src/reflect/type.go15
2 files changed, 95 insertions, 1 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index febbd5f5a7..56d91105a6 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -5891,6 +5891,87 @@ func TestStructOfDifferentPkgPath(t *testing.T) {
})
}
+func TestStructOfTooLarge(t *testing.T) {
+ t1 := TypeOf(byte(0))
+ t2 := TypeOf(int16(0))
+ t4 := TypeOf(int32(0))
+ t0 := ArrayOf(0, t1)
+
+ // 2^64-3 sized type (or 2^32-3 on 32-bit archs)
+ bigType := StructOf([]StructField{
+ {Name: "F1", Type: ArrayOf(int(^uintptr(0)>>1), t1)},
+ {Name: "F2", Type: ArrayOf(int(^uintptr(0)>>1-1), t1)},
+ })
+
+ type test struct {
+ shouldPanic bool
+ fields []StructField
+ }
+
+ tests := [...]test{
+ {
+ shouldPanic: false, // 2^64-1, ok
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(2, t1)},
+ },
+ },
+ {
+ shouldPanic: true, // overflow in total size
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(3, t1)},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while aligning F2
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: t4},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while adding trailing byte for zero-sized fields
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(2, t1)},
+ {Name: "F3", Type: t0},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while aligning total size
+ fields: []StructField{
+ {Name: "F1", Type: t2},
+ {Name: "F2", Type: bigType},
+ },
+ },
+ }
+
+ for i, tt := range tests {
+ func() {
+ defer func() {
+ err := recover()
+ if !tt.shouldPanic {
+ if err != nil {
+ t.Errorf("test %d should not panic, got %s", i, err)
+ }
+ return
+ }
+ if err == nil {
+ t.Errorf("test %d expected to panic", i)
+ return
+ }
+ s := fmt.Sprintf("%s", err)
+ if s != "reflect.StructOf: struct size would exceed virtual address space" {
+ t.Errorf("test %d wrong panic message: %s", i, s)
+ return
+ }
+ }()
+ _ = StructOf(tt.fields)
+ }()
+ }
+}
+
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 7b8cf0ee62..fc591eee69 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -2635,10 +2635,16 @@ func StructOf(fields []StructField) Type {
comparable = comparable && (ft.equal != nil)
offset := align(size, uintptr(ft.align))
+ if offset < size {
+ panic("reflect.StructOf: struct size would exceed virtual address space")
+ }
if ft.align > typalign {
typalign = ft.align
}
size = offset + ft.size
+ if size < offset {
+ panic("reflect.StructOf: struct size would exceed virtual address space")
+ }
f.offset = offset
if ft.size == 0 {
@@ -2655,6 +2661,9 @@ func StructOf(fields []StructField) Type {
// zero-sized field can't manufacture a pointer to the
// next object in the heap. See issue 9401.
size++
+ if size == 0 {
+ panic("reflect.StructOf: struct size would exceed virtual address space")
+ }
}
var typ *structType
@@ -2697,7 +2706,11 @@ func StructOf(fields []StructField) Type {
str := string(repr)
// Round the size up to be a multiple of the alignment.
- size = align(size, uintptr(typalign))
+ s := align(size, uintptr(typalign))
+ if s < size {
+ panic("reflect.StructOf: struct size would exceed virtual address space")
+ }
+ size = s
// Make the struct type.
var istruct any = struct{}{}