runtime: skip zero-sized fields in structs when converting to FFI

The libffi library doesn't understand zero-sized objects.
    When we see a zero-sized field in a struct, just skip it when
    converting to the FFI data structures. There is no value to pass in
    any case, so not telling libffi about the field doesn't affect
    anything.
    
    The test case for this is https://golang.org/cl/123316.
    
    Fixes golang/go#26335
    
    Reviewed-on: https://go-review.googlesource.com/123335

From-SVN: r262651
This commit is contained in:
Ian Lance Taylor 2018-07-13 20:39:02 +00:00
parent 7264261f64
commit 867b003fd7
2 changed files with 46 additions and 4 deletions

View File

@ -1,4 +1,4 @@
3f7e72eca3f9221e67c055841d42851aa6a66aff
db991403fc97854201b3f40492f4f6b9d471cabc
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -225,11 +225,40 @@ func structToFFI(typ *structtype) *__ffi_type {
return emptyStructToFFI()
}
fields := make([]*__ffi_type, c+1)
fields := make([]*__ffi_type, 0, c+1)
checkPad := false
for i, v := range typ.fields {
fields[i] = typeToFFI(v.typ)
// Skip zero-sized fields; they confuse libffi,
// and there is no value to pass in any case.
// We do have to check whether the alignment of the
// zero-sized field introduces any padding for the
// next field.
if v.typ.size == 0 {
checkPad = true
continue
}
if checkPad {
off := uintptr(0)
for j := i - 1; j >= 0; j-- {
if typ.fields[j].typ.size > 0 {
off = typ.fields[j].offset() + typ.fields[j].typ.size
break
}
}
off += uintptr(v.typ.align) - 1
off &^= uintptr(v.typ.align) - 1
if off != v.offset() {
fields = append(fields, padFFI(v.offset()-off))
}
checkPad = false
}
fields = append(fields, typeToFFI(v.typ))
}
fields[c] = nil
fields = append(fields, nil)
return &__ffi_type{
_type: _FFI_TYPE_STRUCT,
elements: &fields[0],
@ -305,6 +334,19 @@ func emptyStructToFFI() *__ffi_type {
}
}
// padFFI returns a padding field of the given size
func padFFI(size uintptr) *__ffi_type {
elements := make([]*__ffi_type, size+1)
for i := uintptr(0); i < size; i++ {
elements[i] = ffi_type_uint8()
}
elements[size] = nil
return &__ffi_type{
_type: _FFI_TYPE_STRUCT,
elements: &elements[0],
}
}
//go:linkname makeCIF reflect.makeCIF
// makeCIF is used by the reflect package to allocate a CIF.