When building to avoid PR go/72812, the 32-bit reflect test FAILs on Solaris/SPARC: Illegal Instruction runtime_sighandler /vol/gcc/src/hg/trunk/local/libgo/runtime/go-signal.c:223 :0 [...] Thread 6 received signal SIGILL, Illegal instruction. [Switching to Thread 4 (LWP 4)] 0xff0d2ea8 in ffi_call_v8 () at /vol/gcc/src/hg/trunk/local/libffi/src/sparc/v8.S:225 225 rept256; rept256; rept256; rept256 1: x/i $pc => 0xff0d2ea8 <ffi_call_v8+440>: illtrap 0x1 (gdb) where #0 0xff0d2ea8 in ffi_call_v8 () at /vol/gcc/src/hg/trunk/local/libffi/src/sparc/v8.S:225 #1 0xfeca7da4 in reflect.call ( func_type=0x981b4 <__go_td_FrN24_reflect_test.emptyStructee>, func_val=0x98188 <reflect_test.returnEmpty$descriptor>, is_interface=<optimized out>, is_method=<optimized out>, params=0x0, results=0x1030cbc8) at /vol/gcc/src/hg/trunk/local/libgo/runtime/go-reflect-call.c:225 #2 0x000b23d0 in reflect.call.N13_reflect.Value ( pointer=pointer@entry=0x111aa590, op=<error reading variable: Cannot access memory at address 0x99>, param=...) at value.go:451 #3 0x000b18cc in reflect.Call.N13_reflect.Value ( pointer=pointer@entry=0x10d71d3c, in=...) at value.go:299 #4 0x000ce690 in reflect_test.TestCallWithStruct (t=0x1074e680) at all_test.go:1509 #5 0xfeda315c in testing.tRunner (param=0x1074e680, fn=0x98310 <reflect_test.TestCallWithStruct$descriptor>) at /vol/gcc/src/hg/trunk/local/libgo/go/testing/testing.go:609 #6 0xfeda31cc in testing.$thunk22 (__go_thunk_parameter=0x1030cb98) at /vol/gcc/src/hg/trunk/local/libgo/go/testing/testing.go:645 #7 0xfecb75bc in kickoff () at /vol/gcc/src/hg/trunk/local/libgo/runtime/proc.c:235 #8 0xfe14a46c in __makecontext_v2 () from /lib/libc.so.1 It seems that the SIGILL is expected here and libgo catching it interferes with libffi. Rainer
The failing test is a function that returns a zero-sized struct. The libffi library does not support a zero-sized struct, so libgo and libffi togther wind up treating the return type as a struct whose size is 1 byte. On 32-bit SPARC, a call to a function that returns a struct whose size is larger than 0 is followed by an unimp instruction. The function is compiled to skip the unimp instruction when it returns. See the handling of %) in sparc_print_operand in gcc/config/sparc/sparc.c. So libffi, thinking that the function returns a non-empty struct, provides an unimp instruction to be skipped. But the actual function returns an empty struct, and therefore does not expect the unimp instruction, and therefore does not skip it. The result is an attempt to execute the instruction, causing the SIGILL.
Author: ian Date: Mon Aug 8 19:53:44 2016 New Revision: 239252 URL: https://gcc.gnu.org/viewcvs?rev=239252&root=gcc&view=rev Log: PR go/72814 runtime: treat zero-sized result value as void Change the FFI interface to treat a call to a function that returns a zero-sized result as a call to a function that returns void. This is part of the fix for https://gcc.gnu.org/PR72814. On 32-bit SPARC systems, a call to a function that returns a non-zero-sized struct is followed by an unimp instruction that describes the size of the struct. The function returns to the address after the unimp instruction. The libffi library can not represent a zero-sized struct, so we wind up treating it as a 1-byte struct. Thus in that case libffi calls the function with an unimp instruction, but the function does not adjust the return address. The result is that the program attempts to execute the unimp instruction, causing a crash. This is part of a change that fixes the crash by treating all functions that return zero bytes as functions that return void. Reviewed-on: https://go-review.googlesource.com/25585 * go-gcc.cc (Gcc_backend::function_type): If the return type is zero bytes, treat the function as returning void. (return_statement): If the return type is zero bytes, don't actually return any values. Modified: trunk/gcc/go/ChangeLog trunk/gcc/go/go-gcc.cc trunk/gcc/go/gofrontend/MERGE trunk/libgo/runtime/go-ffi.c
Fixed.