public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* libgo patch committed: Change handling of empty structs/arrays for libffi
@ 2015-01-16  3:11 Ian Lance Taylor
  0 siblings, 0 replies; only message in thread
From: Ian Lance Taylor @ 2015-01-16  3:11 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 1611 bytes --]

The recent libffi upgrade caused one of the 32-bit x86 libgo tests to
break.  The problem case is a function that returns an empty struct--a
struct with no fields.  The libffi library does not recognize the
existence of empty structs, presumably since they can't happen in C.
To work around this, the Go interface to the libffi library changes an
empty struct to void.  This normally works fine, but with the new
libffi upgrade it fails for a function that returns an empty struct.
On x86 a function that returns a struct is expected to pop the hidden
pointer when it returns.  So when we convert an empty struct to void,
libffi is calling a function that pops the hidden pointer but does not
expect that to happen.

In the older version of libffi, this didn't matter, because the libffi
code for 32-bit x86 used a frame pointer, so the fact that the stack
pointer was wonky when the function returned was ignored as the stack
pointer was immediately replaced by the saved frame pointer.  In the
newer version of libffi, the 32-bit x86 code is more efficient and
does not use a frame pointer, and therefore it matters whether libffi
expects the function to pop the hidden pointer or not.

This patch changes libgo to convert an empty to a struct with a single
field of type void.  This seems to be enough to get the test cases
working again.

Of course the real fix would be to change libffi to handle empty
types, but as libffi uses size == 0 as a marker for an uninitialized
type, that would be a non-trivial change.

Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

[-- Attachment #2: foo.txt --]
[-- Type: text/plain, Size: 1396 bytes --]

diff -r c8b6adce5fa0 libgo/runtime/go-ffi.c
--- a/libgo/runtime/go-ffi.c	Thu Jan 15 14:06:38 2015 -0800
+++ b/libgo/runtime/go-ffi.c	Thu Jan 15 18:43:24 2015 -0800
@@ -52,6 +52,14 @@
   ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
   ret->type = FFI_TYPE_STRUCT;
   len = descriptor->__len;
+  if (len == 0)
+    {
+      /* The libffi library won't accept an empty struct.  */
+      ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
+      ret->elements[0] = &ffi_type_void;
+      ret->elements[1] = NULL;
+      return ret;
+    }
   ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
   element = go_type_to_ffi (descriptor->__element_type);
   for (i = 0; i < len; ++i)
@@ -92,11 +100,16 @@
   int i;
 
   field_count = descriptor->__fields.__count;
-  if (field_count == 0) {
-    return &ffi_type_void;
-  }
   ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
   ret->type = FFI_TYPE_STRUCT;
+  if (field_count == 0)
+    {
+      /* The libffi library won't accept an empty struct.  */
+      ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *));
+      ret->elements[0] = &ffi_type_void;
+      ret->elements[1] = NULL;
+      return ret;
+    }
   fields = (const struct __go_struct_field *) descriptor->__fields.__values;
   ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
 					    * sizeof (ffi_type *));

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-01-16  2:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-16  3:11 libgo patch committed: Change handling of empty structs/arrays for libffi Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).