diff mbox series

libgo patch committed: Skip zero-sized fields in structs when converting to libffi CIF

Message ID CAOyqgcWFh84MQgrM3xM3sOGApsBvGbaGF5rYuhn6oMY++eKd0w@mail.gmail.com
State New
Headers show
Series libgo patch committed: Skip zero-sized fields in structs when converting to libffi CIF | expand

Commit Message

Ian Lance Taylor July 13, 2018, 8:39 p.m. UTC
The libffi library doesn't understand zero-sized objects.  This patch
to libgo fixes it so that when we see a zero-sized field in a struct,
we just skip it when converting to the libffi 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.  This fixes
https://golang.org/issue/26335.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 262641)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -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: libgo/go/runtime/ffi.go
===================================================================
--- libgo/go/runtime/ffi.go	(revision 262540)
+++ libgo/go/runtime/ffi.go	(working copy)
@@ -225,11 +225,40 @@  func structToFFI(typ *structtype) *__ffi
 		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],
@@ -302,6 +331,19 @@  func emptyStructToFFI() *__ffi_type {
 	return &__ffi_type{
 		_type:    _FFI_TYPE_STRUCT,
 		elements: &elements[0],
+	}
+}
+
+// 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],
 	}
 }