]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
runtime: skip zero-sized fields in structs when converting to FFI
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 13 Jul 2018 20:39:02 +0000 (20:39 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 13 Jul 2018 20:39:02 +0000 (20:39 +0000)
    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

gcc/go/gofrontend/MERGE
libgo/go/runtime/ffi.go

index 8aaa045cb6dd906e09d45bcb79689165dbefced2..3e0b65593cd0177bebaa2feca0537e489f048f97 100644 (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.
index 164e1770ea2b55afadd4ac48466e3650ac5a74a1..00858f19ab43e89b2f39a70661a8cfc7e02e5206 100644 (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.