Skip to content

vartuple + inlining causes premature return inside slice element unmarshal (only first element decoded) #430

@wfireleaves

Description

@wfireleaves

Hi maintainers,
I believe I found a bug caused by the interaction of //msgp:vartuple and the inlining pass (parse/inline.go).

What I did

define.go:

//go:generate msgp -tests=false -o define_gen.go define.go
//msgp:vartuple Bag User
type Bag struct {
    ItemID  uint32
    ItemNum uint32
}

type User struct {
    Name string
    Bag  []*Bag
}

What I expected

User.UnmarshalMsg should iterate through Bag []*Bag and unmarshal all elements.

What happened

The generated User.UnmarshalMsg contains return statements inside the per-element decoding logic for Bag (vartuple). Since Bag gets inlined into User.UnmarshalMsg, those returns exit User.UnmarshalMsg early, so decoding stops and later slice elements are not processed.
Relevant generated snippet (inside for za0001 := range z.Bag { ... } ):

zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts)
...
if zb0003 == 0 {
    o = bts
    return
}
...
if zb0003--; zb0003 == 0 {
    o = bts
    return
}

This return is correct if it is inside (*Bag).UnmarshalMsg, but becomes incorrect when Bag is inlined into the outer User.UnmarshalMsg.

Why I think this happens

parse.File() always runs an inlining pass (fs.propInline()).
Inlining replaces small IDENT nodes with a copied gen.Struct.
The vartuple tuple-unmarshal codegen for structs emits early return statements when sz == 0 or after sz-- reaches 0.
When such a struct is inlined into a larger method (e.g., slice element decoding), the early return exits the outer method instead of only stopping the struct decoding.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions