[PATCH, go] Passing Complex64 and Complex128 values via reflect.Call (using libffi) introduces ABI mismatch

Uros Bizjak ubizjak@gmail.com
Fri Mar 1 12:57:00 GMT 2013


Hello!

Due to the fact that libFFI does not handle C99 _Complex arguments
correctly [1], libgo passes Complex64 and Complex128 arguments via a
temporary structure. However, passing parts of complex number in a
structure is not the same as passing true C99 _Complex value, so this
workaround introduces ABI mismatch between caller and callee. This
mismatch results in wrong passed values of complex types.

Fortunately all x86 ABIs tolerate this mismatch, but other targets
(i.e. alpha) don't have this privilege.

Attached patch disables passing of C99 _Complex arguments via FFI on
all targets, other than x86 (to be on the safe side w.r.t. other
targets). Hopefully, someday libffi will be extended to handle
_Complex arguments in correct way.

Patch was tested on x86_64-pc-linux-gnu {,-m32} and alphaev68-pc-linux-gnu.

[1] http://sourceware.org/ml/libffi-discuss/2007/msg00010.html

Uros.
-------------- next part --------------
Index: runtime/go-reflect-call.c
===================================================================
--- runtime/go-reflect-call.c	(revision 196368)
+++ runtime/go-reflect-call.c	(working copy)
@@ -30,7 +30,7 @@
 static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
 static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
 static ffi_type *go_complex_to_ffi (ffi_type *)
-  __attribute__ ((no_split_stack));
+  __attribute__ ((no_split_stack,unused));
 static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
   __attribute__ ((no_split_stack));
 static ffi_type *go_func_return_ffi (const struct __go_func_type *)
@@ -185,13 +185,23 @@
 	return &ffi_type_double;
       abort ();
     case GO_COMPLEX64:
+#if defined (__i386__) || defined (__x86_64__)
       if (sizeof (float) == 4)
 	return go_complex_to_ffi (&ffi_type_float);
       abort ();
+#else
+      runtime_throw("the ABI does not support Complex64 type with "
+		    "reflect.Call or runtime.SetFinalizer");
+#endif
     case GO_COMPLEX128:
+#if defined (__i386__) || defined (__x86_64__)
       if (sizeof (double) == 8)
 	return go_complex_to_ffi (&ffi_type_double);
       abort ();
+#else
+      runtime_throw("the ABI does not support Complex128 type with "
+		    "reflect.Call or runtime.SetFinalizer");
+#endif
     case GO_INT16:
       return &ffi_type_sint16;
     case GO_INT32:
Index: go/testing/quick/quick_test.go
===================================================================
--- go/testing/quick/quick_test.go	(revision 196368)
+++ go/testing/quick/quick_test.go	(working copy)
@@ -7,6 +7,7 @@
 import (
 	"math/rand"
 	"reflect"
+	"runtime"
 	"testing"
 )
 
@@ -72,8 +73,10 @@
 	reportError("fBool", CheckEqual(fBool, fBool, nil), t)
 	reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
 	reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
-	reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
-	reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
+	if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
+		reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
+		reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
+	}
 	reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
 	reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
 	reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t)


More information about the Gcc-patches mailing list