gtk+3.0 FTBFS on ppc64el
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GTK+ |
Fix Released
|
Medium
|
|||
gtk+3.0 (Ubuntu) |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
gtk+3.0 fails to build on ppc64el with a test suite failure in the gtkbuilder tests:
$ cd gtk+3.0-
$ Xvfb -ac -noreset -screen 0 1024x768x16 :0 -nolisten tcp -auth &
$ export DISPLAY=:0.0
$ ./builder
/Builder/Parser: OK
/Builder/Types: OK
/Builder/
/Builder/Children: OK
/Builder/Child Properties: OK
/Builder/Object Properties: OK
/Builder/Notebook: OK
/Builder/Domain: OK
/Builder/Signal Autoconnect: Segmentation fault
$
gdb shows some kind of corrupted backtrace (the calling function is test_connect_
(gdb) bt
#0 0x00003fffb7deeab8 in gtk_window_get_type ()
at /home/buildd/
#1 0x000000001000c8dc in signal_normal (window=<optimized out>, spec=...)
at /home/buildd/
#2 0x00003fffb76c79b0 in g_cclosure_
from /usr/lib/
#3 0x000000001000c8a0 in test_gmenu ()
at /home/buildd/
#4 0x626f3c20203e6563 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
A clean backtrace immediately before the segfault looks like:
#0 signal_normal (window=<optimized out>, spec=...)
at /home/buildd/
#1 0x00003fffb76c7b30 in g_cclosure_
return_
param_
marshal_
#2 0x00003fffb76c3678 in g_closure_invoke (closure=
return_
param_
at /build/
#3 0x00003fffb76dec78 in signal_
instance=
instance_
at /build/
#4 0x00003fffb76e7fc4 in g_signal_
signal_
var_
at /build/
#5 0x00003fffb76e8240 in g_signal_emit (instance=
signal_
at /build/
#6 0x00003fffb76c9e2c in g_object_
object=
at /build/
#7 0x00003fffb76cd864 in g_object_
pspec=
at /build/
#8 g_object_notify (object=0x10200ff0, property_
at /build/
#9 0x00003fffb7df00d4 in gtk_window_
title=
at /home/buildd/
#10 0x00000000100080a8 in test_connect_
at /home/buildd/
#11 0x00003fffb7617ce8 in test_case_run (tc=0x10053a70)
at /build/
#12 g_test_
at /build/
#13 0x00003fffb7617f08 in g_test_
path=
at /build/
#14 0x00003fffb761840c in g_test_run_suite (suite=0x10048ac0)
at /build/
#15 0x00003fffb7618480 in g_test_run ()
at /build/
#16 0x0000000010003ed4 in main (argc=1, argv=0x3fffffff
at /home/buildd/
(gdb)
Stepping through with gdb also shows signal_normal() being entered twice in response to the first gtk_window_
This problem was not evident in the initial bootstrap of gtk+3.0, but now is reproducible on both the launchpad builders and the porter system. It could be due to a kernel upgrade after the initial bootstrap, we're not sure.
Related branches
tags: | added: ftbfs |
tags: | added: ppc64el |
Changed in gtk: | |
importance: | Unknown → Medium |
status: | Unknown → New |
Changed in gtk: | |
status: | New → Fix Released |
This looks like an issue with passing structs by value. g_cclosure_ marshal_ VOID__PARAM is only allocating a 64 byte stack frame and is calling signal_normal via some marshalling tricks. The prototype for signal_normal includes a large struct which will be partially passed in registers and signal_normal expects to be able to write that out to the parameter save area in the callers frame.
signal_normal does end up writing out parameters to the caller stack:
Dump of assembler code for function signal_normal: 00c880 <+0>: lis r2,4099 00c884 <+4>: addi r2,r2,-4080 00c888 <+8>: mflr r0 00c88c <+12>: std r31,-8(r1) 00c890 <+16>: mr r31,r3 00c894 <+20>: std r0,16(r1) 00c898 <+24>: stdu r1,-48(r1) 00c89c <+28>: std r4,88(r1) 00c8a0 <+32>: std r5,96(r1) 00c8a4 <+36>: std r6,104(r1) 00c8a8 <+40>: std r7,112(r1) 00c8ac <+44>: std r8,120(r1) 00c8b0 <+48>: std r9,128(r1) 00c8b4 <+52>: std r10,136(r1)
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
And since g_cclosure_ marshal_ VOID__PARAM hasn't allocated enough stack we stomp all over the stack and die.
What is interesting is that signal_normal doesn't touch the struct, so why are we bothering to save it? It looks like a missing optimisation in gcc and this test case shows it:
struct foo
{
void *a, *b, *c, *d, *e, *f, *g, *h;
#if 1
void *i;
#endif
};
int bar(struct foo foo)
{
return 0;
}
With a struct big enough to not fit into registers, we always save the whole struct out to the stack even if we never touch it:
bar:
std 3,32(1)
std 4,40(1)
li 3,0
std 5,48(1)
std 6,56(1)
std 7,64(1)
std 8,72(1)
std 9,80(1)
std 10,88(1)
blr