lunixbochs / struc

Better binary packing for Go
MIT License
564 stars 42 forks source link

panic on nil pointer field #73

Closed tmm1 closed 4 years ago

tmm1 commented 4 years ago
package main

import "C"
import (
    "bytes"
    "github.com/lunixbochs/struc"
)

type EPGTag struct {
    Title       *C.char
    Description *C.char
}

func main() {
    buf := &bytes.Buffer{}
    var e EPGTag
    e.Title = C.CString("test")
    struc.Pack(buf, &e)
}
panic: reflect: call of reflect.Value.Int on zero Value

goroutine 1 [running]:
reflect.Value.Int(...)
    /usr/local/Cellar/go/1.12.8/libexec/src/reflect/value.go:962
github.com/lunixbochs/struc.(*Field).packVal(0xc0000b0140, 0xc0000c8051, 0x1, 0x1, 0x40da740, 0xc0000a0058, 0x196, 0x1, 0x41deea0, 0x1, ...)
    /Users/tmm1/go/src/github.com/lunixbochs/struc/field.go:102 +0xb1d
github.com/lunixbochs/struc.(*Field).Pack(0xc0000b0140, 0xc0000c8051, 0x1, 0x1, 0x40da740, 0xc0000a0058, 0x196, 0x1, 0x41deea0, 0x1, ...)
    /Users/tmm1/go/src/github.com/lunixbochs/struc/field.go:194 +0x6ba
github.com/lunixbochs/struc.Fields.Pack(0xc0000a0060, 0x2, 0x2, 0xc0000c8050, 0x2, 0x2, 0x40eef60, 0xc0000a0050, 0x199, 0x41deea0, ...)
    /Users/tmm1/go/src/github.com/lunixbochs/struc/fields.go:96 +0x1c9
github.com/lunixbochs/struc.PackWithOptions(0x4129280, 0xc0000a2180, 0x40da700, 0xc0000a0050, 0x41deea0, 0x0, 0x40cb75c)
    /Users/tmm1/go/src/github.com/lunixbochs/struc/struc.go:76 +0x1ea
github.com/lunixbochs/struc.Pack(...)
    /Users/tmm1/go/src/github.com/lunixbochs/struc/struc.go:57
main.main()
    /tmp/test.go:18 +0xb9
exit status 2
tmm1 commented 4 years ago

Okay I understand this a little better now. struc will always dereference pointers to serialize the underlying value, which makes perfect sense for golang types and mimics how json/xml and other serializers work.

In this case C.char is a Uint8, so it serializes an 8-bit int instead of the pointer as I intended.

I'm thinking the best thing to handle my case is to add support in struc for unsafe.Pointer fields. Right now they blow up with:

panic: struc: Could not find field type.

tmm1 commented 4 years ago

Looks like maybe a custom type is the way to go here..

tmm1 commented 4 years ago

Custom type worked!

type cstr struct {
    str *C.char
}

func (c *cstr) Pack(p []byte, opt *struc.Options) (int, error) {
    size := c.Size(opt)
    if size == 4 {
        opt.Order.PutUint32(p[:], uint32(uintptr(unsafe.Pointer(c.str))))
    } else {
        opt.Order.PutUint64(p[:], uint64(uintptr(unsafe.Pointer(c.str))))
    }
    return size, nil
}

func (c *cstr) Unpack(r io.Reader, length int, opt *struc.Options) error {
    panic("unimpl")
}

func (c *cstr) Size(opt *struc.Options) int {
    return (int)(unsafe.Sizeof(uintptr(0)))
}

func (c *cstr) String() string {
    panic("unimpl")
}