Skip to content

Commit b338856

Browse files
randall77gopherbot
authored andcommitted
reflect: handle zero-sized fields of directly-stored structures correctly
type W struct { E struct{} X *byte } type W is a "direct" type. That is, it is a pointer-ish type that can be stored directly as the second word of an interface. But if we ask reflect for W's first field, that value must *not* be direct, as zero-sized things cannot be stored directly. This was a problem introduced in CL 681937. Before that, types like W were not eligible for directness. Fixes #74935 Change-Id: Idefb55c23eaa59153009f863bad611593981e5cb Reviewed-on: https://go-review.googlesource.com/c/go/+/694195 Auto-Submit: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent d83b16f commit b338856

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/reflect/value.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,17 @@ func (v Value) Field(i int) Value {
12771277
fl |= flagStickyRO
12781278
}
12791279
}
1280+
if fl&flagIndir == 0 && typ.Size() == 0 {
1281+
// Special case for picking a field out of a direct struct.
1282+
// A direct struct must have a pointer field and possibly a
1283+
// bunch of zero-sized fields. We must return the zero-sized
1284+
// fields indirectly, as only ptr-shaped things can be direct.
1285+
// See issue 74935.
1286+
// We use nil instead of v.ptr as it doesn't matter and
1287+
// we can avoid pinning a possibly now-unused object.
1288+
return Value{typ, nil, fl | flagIndir}
1289+
}
1290+
12801291
// Either flagIndir is set and v.ptr points at struct,
12811292
// or flagIndir is not set and v.ptr is the actual struct data.
12821293
// In the former case, we want v.ptr + offset.

test/fixedbugs/issue74935.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import "reflect"
10+
11+
type W struct {
12+
E struct{}
13+
X *byte
14+
}
15+
16+
func main() {
17+
w := reflect.ValueOf(W{})
18+
_ = w.Field(0).Interface()
19+
}

0 commit comments

Comments
 (0)