Currently, when marshalig Go types with keyed union fields, we assign the value of the struct (e.g. DomainBuildInfoTypeUnionHvm) which implements the interface of the keyed union field (e.g. DomainBuildInfoTypeUnion). As-is, this means that if a populated DomainBuildInfo is marshaled to e.g. JSON, unmarshaling back to DomainBuildInfo will fail.
When the encoding/json is unmarshaling data into a Go type, and encounters a JSON object, it basically can either marshal the data into an empty interface, a map, or a struct. It cannot, however, marshal data into an interface with at least one method defined on it (e.g. DomainBuildInfoTypeUnion). Before this check is done, however, the decoder will check if the Go type is a pointer, and dereference it if so. It will then use the type of this value as the "target" type. This means that if the TypeUnion field is populated with a DomainBuildInfoTypeUnion, the decoder will see a non-empty interface and fail. If the TypeUnion field is populated with a *DomainBuildInfoTypeUnionHvm, it dereferences the pointer and sees a struct instead, allowing decoding to continue normally. Since there does not appear to be a strict need for NOT using pointers in these fields, update code generation to set keyed union fields to pointers of their implementing structs. Signed-off-by: Nick Rosbrook <rosbro...@ainfosec.com> --- tools/golang/xenlight/gengotypes.py | 4 +-- tools/golang/xenlight/helpers.gen.go | 44 ++++++++++++++-------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py index 3796632f7d..57f2576468 100644 --- a/tools/golang/xenlight/gengotypes.py +++ b/tools/golang/xenlight/gengotypes.py @@ -404,7 +404,7 @@ def xenlight_golang_union_from_C(ty = None, union_name = '', struct_name = ''): s += 'if err := {0}.fromC(xc);'.format(goname) s += 'err != nil {{\n return fmt.Errorf("converting field {0}: %v", err)\n}}\n'.format(goname) - s += 'x.{0} = {1}\n'.format(field_name, goname) + s += 'x.{0} = &{1}\n'.format(field_name, goname) # End switch statement s += 'default:\n' @@ -571,7 +571,7 @@ def xenlight_golang_union_to_C(ty = None, union_name = '', gotype = xenlight_golang_fmt_name(cgotype) field_name = xenlight_golang_fmt_name('{0}_union'.format(keyname)) - s += 'tmp, ok := x.{0}.({1})\n'.format(field_name,gotype) + s += 'tmp, ok := x.{0}.(*{1})\n'.format(field_name,gotype) s += 'if !ok {\n' s += 'return errors.New("wrong type for union key {0}")\n'.format(keyname) s += '}\n' diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go index 5222898fb8..8fc5ec1649 100644 --- a/tools/golang/xenlight/helpers.gen.go +++ b/tools/golang/xenlight/helpers.gen.go @@ -443,7 +443,7 @@ var connectionPty ChannelinfoConnectionUnionPty if err := connectionPty.fromC(xc);err != nil { return fmt.Errorf("converting field connectionPty: %v", err) } -x.ConnectionUnion = connectionPty +x.ConnectionUnion = &connectionPty case ChannelConnectionSocket: x.ConnectionUnion = nil case ChannelConnectionUnknown: @@ -485,7 +485,7 @@ switch x.Connection{ case ChannelConnectionUnknown: break case ChannelConnectionPty: -tmp, ok := x.ConnectionUnion.(ChannelinfoConnectionUnionPty) +tmp, ok := x.ConnectionUnion.(*ChannelinfoConnectionUnionPty) if !ok { return errors.New("wrong type for union key connection") } @@ -1120,7 +1120,7 @@ var typeHvm DomainBuildInfoTypeUnionHvm if err := typeHvm.fromC(xc);err != nil { return fmt.Errorf("converting field typeHvm: %v", err) } -x.TypeUnion = typeHvm +x.TypeUnion = &typeHvm case DomainTypeInvalid: x.TypeUnion = nil case DomainTypePv: @@ -1128,13 +1128,13 @@ var typePv DomainBuildInfoTypeUnionPv if err := typePv.fromC(xc);err != nil { return fmt.Errorf("converting field typePv: %v", err) } -x.TypeUnion = typePv +x.TypeUnion = &typePv case DomainTypePvh: var typePvh DomainBuildInfoTypeUnionPvh if err := typePvh.fromC(xc);err != nil { return fmt.Errorf("converting field typePvh: %v", err) } -x.TypeUnion = typePvh +x.TypeUnion = &typePvh default: return fmt.Errorf("invalid union key '%v'", x.Type)} x.ArchArm.GicVersion = GicVersion(xc.arch_arm.gic_version) @@ -1465,7 +1465,7 @@ xc.tee = C.libxl_tee_type(x.Tee) xc._type = C.libxl_domain_type(x.Type) switch x.Type{ case DomainTypeHvm: -tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionHvm) +tmp, ok := x.TypeUnion.(*DomainBuildInfoTypeUnionHvm) if !ok { return errors.New("wrong type for union key type") } @@ -1593,7 +1593,7 @@ hvm.mca_caps = C.uint64_t(tmp.McaCaps) hvmBytes := C.GoBytes(unsafe.Pointer(&hvm),C.sizeof_libxl_domain_build_info_type_union_hvm) copy(xc.u[:],hvmBytes) case DomainTypePv: -tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionPv) +tmp, ok := x.TypeUnion.(*DomainBuildInfoTypeUnionPv) if !ok { return errors.New("wrong type for union key type") } @@ -1623,7 +1623,7 @@ return fmt.Errorf("converting field E820Host: %v", err) pvBytes := C.GoBytes(unsafe.Pointer(&pv),C.sizeof_libxl_domain_build_info_type_union_pv) copy(xc.u[:],pvBytes) case DomainTypePvh: -tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionPvh) +tmp, ok := x.TypeUnion.(*DomainBuildInfoTypeUnionPvh) if !ok { return errors.New("wrong type for union key type") } @@ -2283,7 +2283,7 @@ var typeHostdev DeviceUsbdevTypeUnionHostdev if err := typeHostdev.fromC(xc);err != nil { return fmt.Errorf("converting field typeHostdev: %v", err) } -x.TypeUnion = typeHostdev +x.TypeUnion = &typeHostdev default: return fmt.Errorf("invalid union key '%v'", x.Type)} @@ -2310,7 +2310,7 @@ xc.port = C.int(x.Port) xc._type = C.libxl_usbdev_type(x.Type) switch x.Type{ case UsbdevTypeHostdev: -tmp, ok := x.TypeUnion.(DeviceUsbdevTypeUnionHostdev) +tmp, ok := x.TypeUnion.(*DeviceUsbdevTypeUnionHostdev) if !ok { return errors.New("wrong type for union key type") } @@ -2508,7 +2508,7 @@ var connectionSocket DeviceChannelConnectionUnionSocket if err := connectionSocket.fromC(xc);err != nil { return fmt.Errorf("converting field connectionSocket: %v", err) } -x.ConnectionUnion = connectionSocket +x.ConnectionUnion = &connectionSocket case ChannelConnectionUnknown: x.ConnectionUnion = nil default: @@ -2546,7 +2546,7 @@ break case ChannelConnectionPty: break case ChannelConnectionSocket: -tmp, ok := x.ConnectionUnion.(DeviceChannelConnectionUnionSocket) +tmp, ok := x.ConnectionUnion.(*DeviceChannelConnectionUnionSocket) if !ok { return errors.New("wrong type for union key connection") } @@ -4107,7 +4107,7 @@ var typeDiskEject EventTypeUnionDiskEject if err := typeDiskEject.fromC(xc);err != nil { return fmt.Errorf("converting field typeDiskEject: %v", err) } -x.TypeUnion = typeDiskEject +x.TypeUnion = &typeDiskEject case EventTypeDomainCreateConsoleAvailable: x.TypeUnion = nil case EventTypeDomainDeath: @@ -4117,13 +4117,13 @@ var typeDomainShutdown EventTypeUnionDomainShutdown if err := typeDomainShutdown.fromC(xc);err != nil { return fmt.Errorf("converting field typeDomainShutdown: %v", err) } -x.TypeUnion = typeDomainShutdown +x.TypeUnion = &typeDomainShutdown case EventTypeOperationComplete: var typeOperationComplete EventTypeUnionOperationComplete if err := typeOperationComplete.fromC(xc);err != nil { return fmt.Errorf("converting field typeOperationComplete: %v", err) } -x.TypeUnion = typeOperationComplete +x.TypeUnion = &typeOperationComplete default: return fmt.Errorf("invalid union key '%v'", x.Type)} @@ -4178,7 +4178,7 @@ xc.for_user = C.uint64_t(x.ForUser) xc._type = C.libxl_event_type(x.Type) switch x.Type{ case EventTypeDomainShutdown: -tmp, ok := x.TypeUnion.(EventTypeUnionDomainShutdown) +tmp, ok := x.TypeUnion.(*EventTypeUnionDomainShutdown) if !ok { return errors.New("wrong type for union key type") } @@ -4189,7 +4189,7 @@ copy(xc.u[:],domain_shutdownBytes) case EventTypeDomainDeath: break case EventTypeDiskEject: -tmp, ok := x.TypeUnion.(EventTypeUnionDiskEject) +tmp, ok := x.TypeUnion.(*EventTypeUnionDiskEject) if !ok { return errors.New("wrong type for union key type") } @@ -4203,7 +4203,7 @@ return fmt.Errorf("converting field Disk: %v", err) disk_ejectBytes := C.GoBytes(unsafe.Pointer(&disk_eject),C.sizeof_libxl_event_type_union_disk_eject) copy(xc.u[:],disk_ejectBytes) case EventTypeOperationComplete: -tmp, ok := x.TypeUnion.(EventTypeUnionOperationComplete) +tmp, ok := x.TypeUnion.(*EventTypeUnionOperationComplete) if !ok { return errors.New("wrong type for union key type") } @@ -4278,13 +4278,13 @@ var typeCat PsrHwInfoTypeUnionCat if err := typeCat.fromC(xc);err != nil { return fmt.Errorf("converting field typeCat: %v", err) } -x.TypeUnion = typeCat +x.TypeUnion = &typeCat case PsrFeatTypeMba: var typeMba PsrHwInfoTypeUnionMba if err := typeMba.fromC(xc);err != nil { return fmt.Errorf("converting field typeMba: %v", err) } -x.TypeUnion = typeMba +x.TypeUnion = &typeMba default: return fmt.Errorf("invalid union key '%v'", x.Type)} @@ -4323,7 +4323,7 @@ xc.id = C.uint32_t(x.Id) xc._type = C.libxl_psr_feat_type(x.Type) switch x.Type{ case PsrFeatTypeCat: -tmp, ok := x.TypeUnion.(PsrHwInfoTypeUnionCat) +tmp, ok := x.TypeUnion.(*PsrHwInfoTypeUnionCat) if !ok { return errors.New("wrong type for union key type") } @@ -4334,7 +4334,7 @@ cat.cdp_enabled = C.bool(tmp.CdpEnabled) catBytes := C.GoBytes(unsafe.Pointer(&cat),C.sizeof_libxl_psr_hw_info_type_union_cat) copy(xc.u[:],catBytes) case PsrFeatTypeMba: -tmp, ok := x.TypeUnion.(PsrHwInfoTypeUnionMba) +tmp, ok := x.TypeUnion.(*PsrHwInfoTypeUnionMba) if !ok { return errors.New("wrong type for union key type") } -- 2.17.1