[ 
https://issues.apache.org/jira/browse/THRIFT-2189?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14295904#comment-14295904
 ] 

Johannes Martinsson commented on THRIFT-2189:
---------------------------------------------

I understand that the wire format does not require the flag. The issue is that
the Go code does *not* know which field is set, or at least it doesn't bother
to check. Because of this when writing a union you can get a runtime panic.

Here follows a simple example with a Thrift definition and small go program
that causes a runtime panic.

{code}
namespace go poc

struct X {
        1: required byte a
}

struct Y {
        1: required byte a
}

union Z {
        1: X x
        2: Y y
}
{code}

And the Go program using the generated code, here placed in a package called 
"poc".

{code}
package main

import (
        "bytes"
        "fmt"
        "poc"

        "git.apache.org/thrift.git/lib/go/thrift"
)

func main() {
        z := poc.Z{
                X: &poc.X{A: int8(1)},
        }

        var b []byte
        buffer := bytes.NewBuffer(b)

        trans := thrift.NewStreamTransportW(buffer)
        proto := thrift.NewTBinaryProtocolTransport(trans)

        z.Write(proto)
        trans.Flush()

        fmt.Printf("Written: %#v\n", buffer.Bytes())
}
{code}

Compiling and running this program generates the following output:

{code}
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x45a718]

goroutine 1 [running]:
poc.(*Y).writeField1(0x0, 0x7f7572620f68, 0xc20805e090, 0x0, 0x0)
        /home/majoh/tmp/thrift-union-poc/src/poc/ttypes.go:195 +0x1b8
poc.(*Y).Write(0x0, 0x7f7572620f68, 0xc20805e090, 0x0, 0x0)
        /home/majoh/tmp/thrift-union-poc/src/poc/ttypes.go:179 +0x1d5
poc.(*Z).writeField2(0xc20800a830, 0x7f7572620f68, 0xc20805e090, 0x0, 0x0)
        /home/majoh/tmp/thrift-union-poc/src/poc/ttypes.go:334 +0x1df
poc.(*Z).Write(0xc20800a830, 0x7f7572620f68, 0xc20805e090, 0x0, 0x0)
        /home/majoh/tmp/thrift-union-poc/src/poc/ttypes.go:305 +0x238
main.main()
        /home/majoh/tmp/thrift-union-poc/poc.go:23 +0x202
exit status 2
{code}

If the thrift definition is altered as to remove the second field of the
union, the program generates the following output:

{code}
Written: []byte{0xc, 0x0, 0x1, 0x3, 0x0, 0x1, 0x1, 0x0, 0x0}
{code}

If instead we keep the original thrift definitions and instead set both fields
of {{z}}, the program generates the following output:

{code}
Written: []byte{0xc, 0x0, 0x1, 0x3, 0x0, 0x1, 0x1, 0x0, 0xc, 0x0, 0x2, 0x3, 
0x0, 0x1, 0x1, 0x0, 0x0}
{code}

(I.e. it is writing both fields, unless I missunderstand how the wire protocol 
works.)

The relevant bit of the generated Go code I believe is the following, which
unconditionally tries to write *all* fields of the union:

{code}
func (p *Z) Write(oprot thrift.TProtocol) error {
        if err := oprot.WriteStructBegin("Z"); err != nil {
                return thrift.PrependError(fmt.Sprintf("%T write struct begin 
error: ", p), err)
        }
        if err := p.writeField1(oprot); err != nil {
                return err
        }
        if err := p.writeField2(oprot); err != nil {
                return err
        }
        if err := oprot.WriteFieldStop(); err != nil {
                return thrift.PrependError("write field stop error: ", err)
        }
        if err := oprot.WriteStructEnd(); err != nil {
                return thrift.PrependError("write struct stop error: ", err)
        }
        return nil
}
{code}


> Go does not support "union" type
> --------------------------------
>
>                 Key: THRIFT-2189
>                 URL: https://issues.apache.org/jira/browse/THRIFT-2189
>             Project: Thrift
>          Issue Type: Bug
>          Components: Go - Compiler
>            Reporter: Jack L
>            Assignee: Jens Geyer
>             Fix For: 1.0
>
>
> Go thrift compiler does not support union types



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to