[v3,1/8] golang/xenlight: Don't try to marshall zero-length arrays in fromC
diff mbox series

Message ID 20200117155734.1067550-1-george.dunlap@citrix.com
State New
Headers show
Series
  • [v3,1/8] golang/xenlight: Don't try to marshall zero-length arrays in fromC
Related show

Commit Message

George Dunlap Jan. 17, 2020, 3:57 p.m. UTC
The current fromC array code will do the "magic" casting and
martialling even when num_foo variable is 0.  Go crashes when doing
the cast.

Only do array marshalling if the number of elements is non-zero;
otherwise, leave the target pointer empty (nil for Go slices, NULL for
C arrays).

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
v2:
- Remove toC part of this, which has been folded into Nick's patch
  series.

CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/gengotypes.py  |   5 +-
 tools/golang/xenlight/helpers.gen.go | 452 +++++++++++++++------------
 2 files changed, 261 insertions(+), 196 deletions(-)

Comments

George Dunlap Jan. 17, 2020, 4:04 p.m. UTC | #1
On 1/17/20 3:57 PM, George Dunlap wrote:
> The current fromC array code will do the "magic" casting and
> martialling even when num_foo variable is 0.  Go crashes when doing
> the cast.
> 
> Only do array marshalling if the number of elements is non-zero;
> otherwise, leave the target pointer empty (nil for Go slices, NULL for
> C arrays).
> 
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
> ---
> v2:
> - Remove toC part of this, which has been folded into Nick's patch
>   series.

Er, obviously the subject line should say "v2", for the whole series. :-/

 -George
Nick Rosbrook Jan. 20, 2020, 11:39 p.m. UTC | #2
Sorry I didn't catch this the first time around, but:

> diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
> index b9a7e828a0..889807d928 100644
> --- a/tools/golang/xenlight/helpers.gen.go
> +++ b/tools/golang/xenlight/helpers.gen.go
> @@ -623,12 +623,14 @@ func (x *SchedParams) toC(xc *C.libxl_sched_params) (err error) {
>
>  func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
>         x.Sched = Scheduler(xc.sched)
> -       numVcpus := int(xc.num_vcpus)
> -       cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
> -       x.Vcpus = make([]SchedParams, numVcpus)
> -       for i, v := range cVcpus {
> -               if err := x.Vcpus[i].fromC(&v); err != nil {
> -                       return err
> +       x.Vcpus = nil
> +       if numVcpus := int(xc.num_vcpus); numVcpus > 0 {


Since `numX` is now scoped to this if block, we could probably just
use `n` or similar and then drop `golenvar` from
`xenlight_golang_array_fromC`. It would remove some pretty ugly
variable names from the generated code :)

-NR
George Dunlap Jan. 21, 2020, 5:35 p.m. UTC | #3
On 1/20/20 11:39 PM, Nick Rosbrook wrote:
>  Sorry I didn't catch this the first time around, but:
> 
>> diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
>> index b9a7e828a0..889807d928 100644
>> --- a/tools/golang/xenlight/helpers.gen.go
>> +++ b/tools/golang/xenlight/helpers.gen.go
>> @@ -623,12 +623,14 @@ func (x *SchedParams) toC(xc *C.libxl_sched_params) (err error) {
>>
>>  func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
>>         x.Sched = Scheduler(xc.sched)
>> -       numVcpus := int(xc.num_vcpus)
>> -       cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
>> -       x.Vcpus = make([]SchedParams, numVcpus)
>> -       for i, v := range cVcpus {
>> -               if err := x.Vcpus[i].fromC(&v); err != nil {
>> -                       return err
>> +       x.Vcpus = nil
>> +       if numVcpus := int(xc.num_vcpus); numVcpus > 0 {
> 
> 
> Since `numX` is now scoped to this if block, we could probably just
> use `n` or similar and then drop `golenvar` from
> `xenlight_golang_array_fromC`. It would remove some pretty ugly
> variable names from the generated code :)

Yes, that looks good.

 -George

Patch
diff mbox series

diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
index 27edf66241..ad2c573da9 100644
--- a/tools/golang/xenlight/gengotypes.py
+++ b/tools/golang/xenlight/gengotypes.py
@@ -419,7 +419,8 @@  def xenlight_golang_array_from_C(ty = None):
     clenvar    = ty.type.lenvar.name
     golenvar   = xenlight_golang_fmt_name(clenvar,exported=False)
 
-    s += '{} := int(xc.{})\n'.format(golenvar, clenvar)
+    s += 'x.{} = nil\n'.format(goname)
+    s += 'if {} := int(xc.{}); {} > 0 {{\n'.format(golenvar, clenvar, golenvar)
     s += '{} := '.format(cslice)
     s +='(*[1<<28]C.{})(unsafe.Pointer(xc.{}))[:{}:{}]\n'.format(ctypename, cname,
                                                                 golenvar, golenvar)
@@ -433,7 +434,7 @@  def xenlight_golang_array_from_C(ty = None):
         s += 'if err := x.{}[i].fromC(&v); err != nil {{\n'.format(goname)
         s += 'return err }\n'
 
-    s += '}\n'
+    s += '}\n}\n'
 
     return s
 
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index b9a7e828a0..889807d928 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -623,12 +623,14 @@  func (x *SchedParams) toC(xc *C.libxl_sched_params) (err error) {
 
 func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
 	x.Sched = Scheduler(xc.sched)
-	numVcpus := int(xc.num_vcpus)
-	cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
-	x.Vcpus = make([]SchedParams, numVcpus)
-	for i, v := range cVcpus {
-		if err := x.Vcpus[i].fromC(&v); err != nil {
-			return err
+	x.Vcpus = nil
+	if numVcpus := int(xc.num_vcpus); numVcpus > 0 {
+		cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
+		x.Vcpus = make([]SchedParams, numVcpus)
+		for i, v := range cVcpus {
+			if err := x.Vcpus[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -691,11 +693,13 @@  func (x *DomainSchedParams) toC(xc *C.libxl_domain_sched_params) (err error) {
 
 func (x *VnodeInfo) fromC(xc *C.libxl_vnode_info) error {
 	x.Memkb = uint64(xc.memkb)
-	numDistances := int(xc.num_distances)
-	cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
-	x.Distances = make([]uint32, numDistances)
-	for i, v := range cDistances {
-		x.Distances[i] = uint32(v)
+	x.Distances = nil
+	if numDistances := int(xc.num_distances); numDistances > 0 {
+		cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
+		x.Distances = make([]uint32, numDistances)
+		for i, v := range cDistances {
+			x.Distances[i] = uint32(v)
+		}
 	}
 	x.Pnode = uint32(xc.pnode)
 	if err := x.Vcpus.fromC(&xc.vcpus); err != nil {
@@ -760,20 +764,24 @@  func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	if err := x.Nodemap.fromC(&xc.nodemap); err != nil {
 		return err
 	}
-	numVcpuHardAffinity := int(xc.num_vcpu_hard_affinity)
-	cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
-	x.VcpuHardAffinity = make([]Bitmap, numVcpuHardAffinity)
-	for i, v := range cVcpuHardAffinity {
-		if err := x.VcpuHardAffinity[i].fromC(&v); err != nil {
-			return err
+	x.VcpuHardAffinity = nil
+	if numVcpuHardAffinity := int(xc.num_vcpu_hard_affinity); numVcpuHardAffinity > 0 {
+		cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
+		x.VcpuHardAffinity = make([]Bitmap, numVcpuHardAffinity)
+		for i, v := range cVcpuHardAffinity {
+			if err := x.VcpuHardAffinity[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVcpuSoftAffinity := int(xc.num_vcpu_soft_affinity)
-	cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
-	x.VcpuSoftAffinity = make([]Bitmap, numVcpuSoftAffinity)
-	for i, v := range cVcpuSoftAffinity {
-		if err := x.VcpuSoftAffinity[i].fromC(&v); err != nil {
-			return err
+	x.VcpuSoftAffinity = nil
+	if numVcpuSoftAffinity := int(xc.num_vcpu_soft_affinity); numVcpuSoftAffinity > 0 {
+		cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
+		x.VcpuSoftAffinity = make([]Bitmap, numVcpuSoftAffinity)
+		for i, v := range cVcpuSoftAffinity {
+			if err := x.VcpuSoftAffinity[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	if err := x.NumaPlacement.fromC(&xc.numa_placement); err != nil {
@@ -798,12 +806,14 @@  func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		return err
 	}
 	x.BlkdevStart = C.GoString(xc.blkdev_start)
-	numVnumaNodes := int(xc.num_vnuma_nodes)
-	cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
-	x.VnumaNodes = make([]VnodeInfo, numVnumaNodes)
-	for i, v := range cVnumaNodes {
-		if err := x.VnumaNodes[i].fromC(&v); err != nil {
-			return err
+	x.VnumaNodes = nil
+	if numVnumaNodes := int(xc.num_vnuma_nodes); numVnumaNodes > 0 {
+		cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
+		x.VnumaNodes = make([]VnodeInfo, numVnumaNodes)
+		for i, v := range cVnumaNodes {
+			if err := x.VnumaNodes[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	x.MaxGrantFrames = uint32(xc.max_grant_frames)
@@ -828,26 +838,32 @@  func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	if err := x.SchedParams.fromC(&xc.sched_params); err != nil {
 		return err
 	}
-	numIoports := int(xc.num_ioports)
-	cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
-	x.Ioports = make([]IoportRange, numIoports)
-	for i, v := range cIoports {
-		if err := x.Ioports[i].fromC(&v); err != nil {
-			return err
+	x.Ioports = nil
+	if numIoports := int(xc.num_ioports); numIoports > 0 {
+		cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
+		x.Ioports = make([]IoportRange, numIoports)
+		for i, v := range cIoports {
+			if err := x.Ioports[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numIrqs := int(xc.num_irqs)
-	cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
-	x.Irqs = make([]uint32, numIrqs)
-	for i, v := range cIrqs {
-		x.Irqs[i] = uint32(v)
+	x.Irqs = nil
+	if numIrqs := int(xc.num_irqs); numIrqs > 0 {
+		cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
+		x.Irqs = make([]uint32, numIrqs)
+		for i, v := range cIrqs {
+			x.Irqs[i] = uint32(v)
+		}
 	}
-	numIomem := int(xc.num_iomem)
-	cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
-	x.Iomem = make([]IomemRange, numIomem)
-	for i, v := range cIomem {
-		if err := x.Iomem[i].fromC(&v); err != nil {
-			return err
+	x.Iomem = nil
+	if numIomem := int(xc.num_iomem); numIomem > 0 {
+		cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
+		x.Iomem = make([]IomemRange, numIomem)
+		for i, v := range cIomem {
+			if err := x.Iomem[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	if err := x.ClaimMode.fromC(&xc.claim_mode); err != nil {
@@ -878,18 +894,18 @@  func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.Tee = TeeType(xc.tee)
 	x.Type = DomainType(xc._type)
 	switch x.Type {
-	case DomainTypePv:
-		var typePv DomainBuildInfoTypeUnionPv
-		if err := typePv.fromC(xc); err != nil {
-			return err
-		}
-		x.TypeUnion = typePv
 	case DomainTypeHvm:
 		var typeHvm DomainBuildInfoTypeUnionHvm
 		if err := typeHvm.fromC(xc); err != nil {
 			return err
 		}
 		x.TypeUnion = typeHvm
+	case DomainTypePv:
+		var typePv DomainBuildInfoTypeUnionPv
+		if err := typePv.fromC(xc); err != nil {
+			return err
+		}
+		x.TypeUnion = typePv
 	case DomainTypePvh:
 		var typePvh DomainBuildInfoTypeUnionPvh
 		if err := typePvh.fromC(xc); err != nil {
@@ -2187,12 +2203,14 @@  func (x *DeviceVdispl) fromC(xc *C.libxl_device_vdispl) error {
 	x.BackendDomname = C.GoString(xc.backend_domname)
 	x.Devid = Devid(xc.devid)
 	x.BeAlloc = bool(xc.be_alloc)
-	numConnectors := int(xc.num_connectors)
-	cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	x.Connectors = make([]ConnectorParam, numConnectors)
-	for i, v := range cConnectors {
-		if err := x.Connectors[i].fromC(&v); err != nil {
-			return err
+	x.Connectors = nil
+	if numConnectors := int(xc.num_connectors); numConnectors > 0 {
+		cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		x.Connectors = make([]ConnectorParam, numConnectors)
+		for i, v := range cConnectors {
+			if err := x.Connectors[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2227,17 +2245,21 @@  func (x *DeviceVdispl) toC(xc *C.libxl_device_vdispl) (err error) {
 }
 
 func (x *VsndParams) fromC(xc *C.libxl_vsnd_params) error {
-	numSampleRates := int(xc.num_sample_rates)
-	cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
-	x.SampleRates = make([]uint32, numSampleRates)
-	for i, v := range cSampleRates {
-		x.SampleRates[i] = uint32(v)
-	}
-	numSampleFormats := int(xc.num_sample_formats)
-	cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
-	x.SampleFormats = make([]VsndPcmFormat, numSampleFormats)
-	for i, v := range cSampleFormats {
-		x.SampleFormats[i] = VsndPcmFormat(v)
+	x.SampleRates = nil
+	if numSampleRates := int(xc.num_sample_rates); numSampleRates > 0 {
+		cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
+		x.SampleRates = make([]uint32, numSampleRates)
+		for i, v := range cSampleRates {
+			x.SampleRates[i] = uint32(v)
+		}
+	}
+	x.SampleFormats = nil
+	if numSampleFormats := int(xc.num_sample_formats); numSampleFormats > 0 {
+		cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
+		x.SampleFormats = make([]VsndPcmFormat, numSampleFormats)
+		for i, v := range cSampleFormats {
+			x.SampleFormats[i] = VsndPcmFormat(v)
+		}
 	}
 	x.ChannelsMin = uint32(xc.channels_min)
 	x.ChannelsMax = uint32(xc.channels_max)
@@ -2309,12 +2331,14 @@  func (x *VsndPcm) fromC(xc *C.libxl_vsnd_pcm) error {
 	if err := x.Params.fromC(&xc.params); err != nil {
 		return err
 	}
-	numVsndStreams := int(xc.num_vsnd_streams)
-	cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	x.Streams = make([]VsndStream, numVsndStreams)
-	for i, v := range cStreams {
-		if err := x.Streams[i].fromC(&v); err != nil {
-			return err
+	x.Streams = nil
+	if numVsndStreams := int(xc.num_vsnd_streams); numVsndStreams > 0 {
+		cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		x.Streams = make([]VsndStream, numVsndStreams)
+		for i, v := range cStreams {
+			if err := x.Streams[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2357,12 +2381,14 @@  func (x *DeviceVsnd) fromC(xc *C.libxl_device_vsnd) error {
 	if err := x.Params.fromC(&xc.params); err != nil {
 		return err
 	}
-	numVsndPcms := int(xc.num_vsnd_pcms)
-	cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	x.Pcms = make([]VsndPcm, numVsndPcms)
-	for i, v := range cPcms {
-		if err := x.Pcms[i].fromC(&v); err != nil {
-			return err
+	x.Pcms = nil
+	if numVsndPcms := int(xc.num_vsnd_pcms); numVsndPcms > 0 {
+		cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		x.Pcms = make([]VsndPcm, numVsndPcms)
+		for i, v := range cPcms {
+			if err := x.Pcms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2411,124 +2437,154 @@  func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 	if err := x.BInfo.fromC(&xc.b_info); err != nil {
 		return err
 	}
-	numDisks := int(xc.num_disks)
-	cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
-	x.Disks = make([]DeviceDisk, numDisks)
-	for i, v := range cDisks {
-		if err := x.Disks[i].fromC(&v); err != nil {
-			return err
+	x.Disks = nil
+	if numDisks := int(xc.num_disks); numDisks > 0 {
+		cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
+		x.Disks = make([]DeviceDisk, numDisks)
+		for i, v := range cDisks {
+			if err := x.Disks[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numNics := int(xc.num_nics)
-	cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
-	x.Nics = make([]DeviceNic, numNics)
-	for i, v := range cNics {
-		if err := x.Nics[i].fromC(&v); err != nil {
-			return err
+	x.Nics = nil
+	if numNics := int(xc.num_nics); numNics > 0 {
+		cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
+		x.Nics = make([]DeviceNic, numNics)
+		for i, v := range cNics {
+			if err := x.Nics[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numPcidevs := int(xc.num_pcidevs)
-	cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
-	x.Pcidevs = make([]DevicePci, numPcidevs)
-	for i, v := range cPcidevs {
-		if err := x.Pcidevs[i].fromC(&v); err != nil {
-			return err
+	x.Pcidevs = nil
+	if numPcidevs := int(xc.num_pcidevs); numPcidevs > 0 {
+		cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
+		x.Pcidevs = make([]DevicePci, numPcidevs)
+		for i, v := range cPcidevs {
+			if err := x.Pcidevs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numRdms := int(xc.num_rdms)
-	cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
-	x.Rdms = make([]DeviceRdm, numRdms)
-	for i, v := range cRdms {
-		if err := x.Rdms[i].fromC(&v); err != nil {
-			return err
+	x.Rdms = nil
+	if numRdms := int(xc.num_rdms); numRdms > 0 {
+		cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
+		x.Rdms = make([]DeviceRdm, numRdms)
+		for i, v := range cRdms {
+			if err := x.Rdms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numDtdevs := int(xc.num_dtdevs)
-	cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
-	x.Dtdevs = make([]DeviceDtdev, numDtdevs)
-	for i, v := range cDtdevs {
-		if err := x.Dtdevs[i].fromC(&v); err != nil {
-			return err
+	x.Dtdevs = nil
+	if numDtdevs := int(xc.num_dtdevs); numDtdevs > 0 {
+		cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
+		x.Dtdevs = make([]DeviceDtdev, numDtdevs)
+		for i, v := range cDtdevs {
+			if err := x.Dtdevs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVfbs := int(xc.num_vfbs)
-	cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
-	x.Vfbs = make([]DeviceVfb, numVfbs)
-	for i, v := range cVfbs {
-		if err := x.Vfbs[i].fromC(&v); err != nil {
-			return err
+	x.Vfbs = nil
+	if numVfbs := int(xc.num_vfbs); numVfbs > 0 {
+		cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
+		x.Vfbs = make([]DeviceVfb, numVfbs)
+		for i, v := range cVfbs {
+			if err := x.Vfbs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVkbs := int(xc.num_vkbs)
-	cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
-	x.Vkbs = make([]DeviceVkb, numVkbs)
-	for i, v := range cVkbs {
-		if err := x.Vkbs[i].fromC(&v); err != nil {
-			return err
+	x.Vkbs = nil
+	if numVkbs := int(xc.num_vkbs); numVkbs > 0 {
+		cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
+		x.Vkbs = make([]DeviceVkb, numVkbs)
+		for i, v := range cVkbs {
+			if err := x.Vkbs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVtpms := int(xc.num_vtpms)
-	cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
-	x.Vtpms = make([]DeviceVtpm, numVtpms)
-	for i, v := range cVtpms {
-		if err := x.Vtpms[i].fromC(&v); err != nil {
-			return err
+	x.Vtpms = nil
+	if numVtpms := int(xc.num_vtpms); numVtpms > 0 {
+		cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
+		x.Vtpms = make([]DeviceVtpm, numVtpms)
+		for i, v := range cVtpms {
+			if err := x.Vtpms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numP9S := int(xc.num_p9s)
-	cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
-	x.P9S = make([]DeviceP9, numP9S)
-	for i, v := range cP9S {
-		if err := x.P9S[i].fromC(&v); err != nil {
-			return err
+	x.P9S = nil
+	if numP9S := int(xc.num_p9s); numP9S > 0 {
+		cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
+		x.P9S = make([]DeviceP9, numP9S)
+		for i, v := range cP9S {
+			if err := x.P9S[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numPvcallsifs := int(xc.num_pvcallsifs)
-	cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
-	x.Pvcallsifs = make([]DevicePvcallsif, numPvcallsifs)
-	for i, v := range cPvcallsifs {
-		if err := x.Pvcallsifs[i].fromC(&v); err != nil {
-			return err
+	x.Pvcallsifs = nil
+	if numPvcallsifs := int(xc.num_pvcallsifs); numPvcallsifs > 0 {
+		cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
+		x.Pvcallsifs = make([]DevicePvcallsif, numPvcallsifs)
+		for i, v := range cPvcallsifs {
+			if err := x.Pvcallsifs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVdispls := int(xc.num_vdispls)
-	cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
-	x.Vdispls = make([]DeviceVdispl, numVdispls)
-	for i, v := range cVdispls {
-		if err := x.Vdispls[i].fromC(&v); err != nil {
-			return err
+	x.Vdispls = nil
+	if numVdispls := int(xc.num_vdispls); numVdispls > 0 {
+		cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
+		x.Vdispls = make([]DeviceVdispl, numVdispls)
+		for i, v := range cVdispls {
+			if err := x.Vdispls[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVsnds := int(xc.num_vsnds)
-	cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
-	x.Vsnds = make([]DeviceVsnd, numVsnds)
-	for i, v := range cVsnds {
-		if err := x.Vsnds[i].fromC(&v); err != nil {
-			return err
+	x.Vsnds = nil
+	if numVsnds := int(xc.num_vsnds); numVsnds > 0 {
+		cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
+		x.Vsnds = make([]DeviceVsnd, numVsnds)
+		for i, v := range cVsnds {
+			if err := x.Vsnds[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numChannels := int(xc.num_channels)
-	cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
-	x.Channels = make([]DeviceChannel, numChannels)
-	for i, v := range cChannels {
-		if err := x.Channels[i].fromC(&v); err != nil {
-			return err
+	x.Channels = nil
+	if numChannels := int(xc.num_channels); numChannels > 0 {
+		cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
+		x.Channels = make([]DeviceChannel, numChannels)
+		for i, v := range cChannels {
+			if err := x.Channels[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numUsbctrls := int(xc.num_usbctrls)
-	cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
-	x.Usbctrls = make([]DeviceUsbctrl, numUsbctrls)
-	for i, v := range cUsbctrls {
-		if err := x.Usbctrls[i].fromC(&v); err != nil {
-			return err
+	x.Usbctrls = nil
+	if numUsbctrls := int(xc.num_usbctrls); numUsbctrls > 0 {
+		cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
+		x.Usbctrls = make([]DeviceUsbctrl, numUsbctrls)
+		for i, v := range cUsbctrls {
+			if err := x.Usbctrls[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numUsbdevs := int(xc.num_usbdevs)
-	cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
-	x.Usbdevs = make([]DeviceUsbdev, numUsbdevs)
-	for i, v := range cUsbdevs {
-		if err := x.Usbdevs[i].fromC(&v); err != nil {
-			return err
+	x.Usbdevs = nil
+	if numUsbdevs := int(xc.num_usbdevs); numUsbdevs > 0 {
+		cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
+		x.Usbdevs = make([]DeviceUsbdev, numUsbdevs)
+		for i, v := range cUsbdevs {
+			if err := x.Usbdevs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	x.OnPoweroff = ActionOnShutdown(xc.on_poweroff)
@@ -3012,12 +3068,14 @@  func (x *Vdisplinfo) fromC(xc *C.libxl_vdisplinfo) error {
 	x.Devid = Devid(xc.devid)
 	x.State = int(xc.state)
 	x.BeAlloc = bool(xc.be_alloc)
-	numConnectors := int(xc.num_connectors)
-	cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	x.Connectors = make([]Connectorinfo, numConnectors)
-	for i, v := range cConnectors {
-		if err := x.Connectors[i].fromC(&v); err != nil {
-			return err
+	x.Connectors = nil
+	if numConnectors := int(xc.num_connectors); numConnectors > 0 {
+		cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		x.Connectors = make([]Connectorinfo, numConnectors)
+		for i, v := range cConnectors {
+			if err := x.Connectors[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -3077,12 +3135,14 @@  func (x *Streaminfo) toC(xc *C.libxl_streaminfo) (err error) {
 }
 
 func (x *Pcminfo) fromC(xc *C.libxl_pcminfo) error {
-	numVsndStreams := int(xc.num_vsnd_streams)
-	cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	x.Streams = make([]Streaminfo, numVsndStreams)
-	for i, v := range cStreams {
-		if err := x.Streams[i].fromC(&v); err != nil {
-			return err
+	x.Streams = nil
+	if numVsndStreams := int(xc.num_vsnd_streams); numVsndStreams > 0 {
+		cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		x.Streams = make([]Streaminfo, numVsndStreams)
+		for i, v := range cStreams {
+			if err := x.Streams[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -3117,12 +3177,14 @@  func (x *Vsndinfo) fromC(xc *C.libxl_vsndinfo) error {
 	x.FrontendId = uint32(xc.frontend_id)
 	x.Devid = Devid(xc.devid)
 	x.State = int(xc.state)
-	numVsndPcms := int(xc.num_vsnd_pcms)
-	cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	x.Pcms = make([]Pcminfo, numVsndPcms)
-	for i, v := range cPcms {
-		if err := x.Pcms[i].fromC(&v); err != nil {
-			return err
+	x.Pcms = nil
+	if numVsndPcms := int(xc.num_vsnd_pcms); numVsndPcms > 0 {
+		cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		x.Pcms = make([]Pcminfo, numVsndPcms)
+		for i, v := range cPcms {
+			if err := x.Pcms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -3199,11 +3261,13 @@  func (x *Vkbinfo) toC(xc *C.libxl_vkbinfo) (err error) {
 func (x *Numainfo) fromC(xc *C.libxl_numainfo) error {
 	x.Size = uint64(xc.size)
 	x.Free = uint64(xc.free)
-	numDists := int(xc.num_dists)
-	cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
-	x.Dists = make([]uint32, numDists)
-	for i, v := range cDists {
-		x.Dists[i] = uint32(v)
+	x.Dists = nil
+	if numDists := int(xc.num_dists); numDists > 0 {
+		cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
+		x.Dists = make([]uint32, numDists)
+		for i, v := range cDists {
+			x.Dists[i] = uint32(v)
+		}
 	}
 
 	return nil