Skip to content

Commit

Permalink
fix(reflect): deep nested struct cause panic
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaost committed Dec 4, 2024
1 parent 7402993 commit f40ffab
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 11 deletions.
35 changes: 24 additions & 11 deletions internal/reflect/desc.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,36 @@ func newStructDescAndPrefetch(t reflect.Type) (*structDesc, error) {

func prefetchSubStructDesc(d *structDesc) error {
for i := range d.fields {
var t *tType
f := d.fields[i]
if f.Type.T == tSTRUCT {
t = f.Type
} else if f.Type.T == tMAP && f.Type.V.T == tSTRUCT {
t = f.Type.V
} else if f.Type.T == tLIST && f.Type.V.T == tSTRUCT {
t = f.Type.V
} else {
continue
switch f.Type.T {
case tSTRUCT, tMAP, tLIST, tSET:
if err := fetchStructDesc(f.Type); err != nil {
return err
}
}
sd, err := newStructDescAndPrefetch(t.RT)
}
return nil
}

func fetchStructDesc(t *tType) error {
if t.T == tMAP {
err := fetchStructDesc(t.K)
if err != nil {
return err
}
t.Sd = sd
return fetchStructDesc(t.V)
}
if t.T == tLIST || t.T == tSET {
return fetchStructDesc(t.V)
}
if t.T != tSTRUCT || t.Sd != nil {
return nil
}
sd, err := newStructDescAndPrefetch(t.RT)
if err != nil {
return err
}
t.Sd = sd
return nil
}

Expand Down
25 changes: 25 additions & 0 deletions internal/reflect/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,28 @@ func TestEncodeUnknownFields(t *testing.T) {
assert.Equal(t, n, len(b))
assert.Contains(t, string(b), string(append([]byte("helloworld")[:], byte(tSTOP))))
}

func TestNestedListMapStruct(t *testing.T) {
type Msg1 struct {
A string `frugal:"1,default,string"`
B string `frugal:"2,default,string"`
}
type Msg2 struct {
Msgs []map[string]*Msg1 `thrift:"item_list,2" frugal:"2,default,list<map<string:Msg1>>" json:"item_list"`
}
p := &Msg2{}
p.Msgs = make([]map[string]*Msg1, 0, 1)
p.Msgs = append(p.Msgs, map[string]*Msg1{})
p.Msgs[0]["32"] = &Msg1{A: "Hello", B: "World"}

b := make([]byte, EncodedSize(p))
i, err := Encode(b, p)

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: Encode (typecheck)

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.18, X64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.19, X64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.20, X64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-arm64 (1.19, ARM64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.21, X64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.22, X64)

undefined: Encode

Check failure on line 163 in internal/reflect/encoder_test.go

View workflow job for this annotation

GitHub Actions / compatibility-test-amd64 (1.23, X64)

undefined: Encode
require.NoError(t, err)
require.Equal(t, i, len(b))

p2 := &Msg2{}
i, err = Decode(b, p2)
require.NoError(t, err)
require.Equal(t, i, len(b))
require.Equal(t, p, p2)
}

0 comments on commit f40ffab

Please sign in to comment.