lunixbochs / struc

Better binary packing for Go
MIT License
576 stars 45 forks source link

Packing value fails unless struct was unpacked before #81

Open zonque opened 4 years ago

zonque commented 4 years ago

I've bumped into this weird issue and I still can't make sense of it.

Consider the following example:

package main

import (
    "bytes"
    "fmt"

    "github.com/lunixbochs/struc"
)

type example struct {
    A int `struc:"little"`
}

func read(buf *bytes.Buffer) {
    o := example{}
    err := struc.Unpack(buf, &o)
    if err != nil {
        panic(err)
    }
}

func write(buf *bytes.Buffer, data interface{}) {
    err := struc.Pack(buf, data)
    if err != nil {
        panic(err)
    }
}

func main() {
    o := example{123}

    buf := bytes.NewBuffer([]byte{})

    write(buf, o)
    fmt.Println(buf.Bytes())
}

The above doesn't work, the buffer remains empty. It can be fixed by passing o as a pointer:

    write(buf, &o)
    fmt.Println(buf.Bytes())

Now, the weird thing is: if the example struct is once unpacked before the packing, it works regardless of whether the struct is passed by value or by pointer.

func main() {
    o := example{123}

    buf := bytes.NewBuffer([]byte{0, 0, 0, 0})

    read(buf)
    fmt.Println(buf.Bytes())

    write(buf, o)
    fmt.Println(buf.Bytes())
}

This is not specific to the instance of the struct but a global effect. As long as the unpacking happened once in the running task, packing works fine.

Can anyone make sense of that? I'm not even sure if this is a bug.

zonque commented 4 years ago

FWIW, this is

go version go1.14.3 linux/amd64

and

github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe
lunixbochs commented 4 years ago

maybe put some basic prints in the parseFields call tree and see when it's being called

https://github.com/lunixbochs/struc/blob/a4cb8d33dbbefdc90689dbcaff46393d6c9cfb97/parse.go#L200