summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-16 02:54:13 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-16 02:54:13 +0000
commit09ec9cdf9949592e570e04b543a002a1a33e60f8 (patch)
treeda5fdc2fe05b13b5665eb574ae14986f1e4f9292 /libgo
parent16e50f8223e480c1462864f7bc9d74eaa70e8936 (diff)
downloadgcc-09ec9cdf9949592e570e04b543a002a1a33e60f8.tar.gz
runtime: Use a struct, not void, for an empty struct for libffi.
A recent libffi upgrade caused the reflect test to fail on 386. 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 386 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 386 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 386 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@219701 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r--libgo/runtime/go-ffi.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c
index 21879b95b77..175c583bf45 100644
--- a/libgo/runtime/go-ffi.c
+++ b/libgo/runtime/go-ffi.c
@@ -52,6 +52,14 @@ go_array_to_ffi (const struct __go_array_type *descriptor)
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 @@ go_struct_to_ffi (const struct __go_struct_type *descriptor)
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 *));