ugorji / go

idiomatic codec and rpc lib for msgpack, cbor, json, etc. msgpack.org[Go]
MIT License
1.85k stars 295 forks source link

Weird behaviour when implementing BinaryMarshaler and BinaryUnmarshaler #342

Closed defgenx closed 3 years ago

defgenx commented 3 years ago

Hi.

I tried to create a struct that implement BinaryMarshaler and BinaryUnmarshaler and my program produce the following error:

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc03fa00390 stack=[0xc03fa00000, 0xc05fa00000]
fatal error: stack overflow

Here is the code:

package main

import (
    "bytes"
    "github.com/ugorji/go/codec"
    "log"
)

type Source struct {
    Name string
}

func (s Source) MarshalBinary() ([]byte, error) {
    var buffer bytes.Buffer
    handler := new(codec.MsgpackHandle)
    encoder := codec.NewEncoder(&buffer, handler)
    err := encoder.Encode(s)
    if err != nil {
        return nil, err
    }
    return buffer.Bytes(), nil
}

func (s *Source) UnmarshalBinary(data []byte) error {
    handler := new(codec.MsgpackHandle)
    reader := bytes.NewReader(data)
    decoder := codec.NewDecoder(reader, handler)
    err := decoder.Decode(&s)
    if err != nil {
        return err
    }
   return nil
}

func main() {
    log.Print(new(Source).MarshalBinary())
}

Maybe I did something wrong but I don't have the same behaviour with the encoding/json package. Can you explain me what is going on here ?

Thanks a lot !

ugorji commented 3 years ago

This package supports MarshalBinary and UnmarshalBinary (along with the Text and JSON variants).

Consequently, you should not use it to implement these functions, else you get into a loop (as seen).

i.e.

That's the loop.

encoding/json doesn't have this issue, because encoding/json only supports MarshalText/MarshalJSON. I reckon implementing those methods will cause same issue.