Skip to content

Commit 296b353

Browse files
thoenirsc
authored andcommitted
encoding/json: don't marshal unexported embedded fields of non struct type
Marshal must process unexported embedded fields of struct type, looking for exported fields in those structs. However, it must not process unexported embedded fields of non-struct type. For example, consider: type t1 struct { X int } type t2 int type T struct { t1 t2 } When considering T, Marshal must process t1 to find t1.X. Marshal must not process t2, but it was. Fix that. Fixes #18009 Change-Id: I62ba0b65ba30fd927990e101a26405a9998787a3 Reviewed-on: https://go-review.googlesource.com/33773 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent e2160cc commit 296b353

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

src/encoding/json/encode.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ func typeFields(t reflect.Type) []field {
10931093
// Scan f.typ for fields to include.
10941094
for i := 0; i < f.typ.NumField(); i++ {
10951095
sf := f.typ.Field(i)
1096-
if sf.PkgPath != "" && !sf.Anonymous { // unexported
1096+
if sf.PkgPath != "" && (!sf.Anonymous || sf.Type.Kind() != reflect.Struct) { // unexported
10971097
continue
10981098
}
10991099
tag := sf.Tag.Get("json")

src/encoding/json/encode_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,59 @@ func TestAnonymousNonstruct(t *testing.T) {
273273
}
274274
}
275275

276+
type unexportedIntType int
277+
278+
type MyStructWithUnexportedIntType struct {
279+
unexportedIntType
280+
}
281+
282+
func TestAnonymousNonstructWithUnexportedType(t *testing.T) {
283+
a := MyStructWithUnexportedIntType{11}
284+
const want = `{}`
285+
286+
b, err := Marshal(a)
287+
if err != nil {
288+
t.Fatalf("Marshal: %v", err)
289+
}
290+
if got := string(b); got != want {
291+
t.Errorf("got %q, want %q", got, want)
292+
}
293+
}
294+
295+
type MyStructContainingUnexportedStruct struct {
296+
unexportedStructType1
297+
unexportedIntType
298+
}
299+
300+
type unexportedStructType1 struct {
301+
ExportedIntType1
302+
unexportedIntType
303+
unexportedStructType2
304+
}
305+
306+
type unexportedStructType2 struct {
307+
ExportedIntType2
308+
unexportedIntType
309+
}
310+
311+
type ExportedIntType1 int
312+
type ExportedIntType2 int
313+
314+
func TestUnexportedAnonymousStructWithExportedType(t *testing.T) {
315+
s2 := unexportedStructType2{3, 4}
316+
s1 := unexportedStructType1{1, 2, s2}
317+
a := MyStructContainingUnexportedStruct{s1, 6}
318+
const want = `{"ExportedIntType1":1,"ExportedIntType2":3}`
319+
320+
b, err := Marshal(a)
321+
if err != nil {
322+
t.Fatalf("Marshal: %v", err)
323+
}
324+
if got := string(b); got != want {
325+
t.Errorf("got %q, want %q", got, want)
326+
}
327+
}
328+
276329
type BugA struct {
277330
S string
278331
}

0 commit comments

Comments
 (0)