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

Change-Id: Ifebefee76596508990c900c58af48be08a549674
Reviewed-on: https://go-review.googlesource.com/123335
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/libgo/go/runtime/ffi.go b/libgo/go/runtime/ffi.go
index 164e177..00858f1 100644
--- a/libgo/go/runtime/ffi.go
+++ b/libgo/go/runtime/ffi.go
@@ -225,11 +225,40 @@
 		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 @@
 	}
 }
 
+// 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.