Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bug#591075: glib2.0 segv

5 views
Skip to first unread message

Jan Christoph Nordholz

unread,
Aug 4, 2010, 8:30:01 PM8/4/10
to
Hi,

probably an optimization problem? Given the test program

====
extern void g_type_init(void);

int main(int an, char **ac) {
(void)g_type_init();
return 0;
}
====

I get this backtrace:

====
#0 g_bsearch_array_create ()
at /build/buildd-glib2.0_2.25.12-1-i386-5iccNM/glib2.0-2.25.12/glib/gbsearcharray.h:137
#1 g_signal_init ()
at /build/buildd-glib2.0_2.25.12-1-i386-5iccNM/glib2.0-2.25.12/gobject/gsignal.c:775
#2 0xb7fafaef in g_type_init_with_debug_flags (debug_flags=G_TYPE_DEBUG_NONE)
at /build/buildd-glib2.0_2.25.12-1-i386-5iccNM/glib2.0-2.25.12/gobject/gtype.c:4349
#3 0xb7fafc2e in g_type_init ()
at /build/buildd-glib2.0_2.25.12-1-i386-5iccNM/glib2.0-2.25.12/gobject/gtype.c:4367
#4 0x080484bf in main (an=1, ac=0xbffff614) at x.c:4
====

Now a close look at g_signal_init():

#1 C Source
==== g_signal_init()
[...]
g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
g_signal_key_bsa = g_bsearch_array_create (&g_signal_key_bconfig);
[...]
==== [inline] g_bsearch_array_create()
static inline GBSearchArray*
g_bsearch_array_create (const GBSearchConfig *bconfig)
{
GBSearchArray *barray;
guint size;

g_return_val_if_fail (bconfig != NULL, NULL);

size = sizeof (GBSearchArray) + bconfig->sizeof_node;
if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2)
size = G_BSEARCH_UPPER_POWER2 (size);
barray = (GBSearchArray *) g_malloc (size);
memset (barray, 0, sizeof (GBSearchArray));

return barray;
}
====

#2 Assembler
==== <g_signal_init>
[...]
0xb7fa5297 <+167>: mov eax,DWORD PTR [ebx-0x30]
0xb7fa529d <+173>: mov DWORD PTR [esp+0x4],0x0
0xb7fa52a5 <+181>: mov DWORD PTR [esp],eax
0xb7fa52a8 <+184>: call 0xb7f8c714 <g_hash_table_new@plt>
0xb7fa52ad <+189>: mov DWORD PTR [esp],0x0
0xb7fa52b4 <+196>: mov DWORD PTR [ebx+0x504],eax
0xb7fa52ba <+202>: call 0xb7f8c614 <g_malloc@plt>
=> 0xb7fa52bf <+207>: mov DWORD PTR [eax],0x0
0xb7fa52c5 <+213>: mov DWORD PTR [eax+0x4],0x0
[...]
====

This is effectively "*(GBSearchArray *)g_malloc(0) = {0, 0}" and MUST fail.
(Where the rest of the inlined function has gone is beyond my comprehension.)
Recompiling the package without optimization makes g_bsearch_array_create() a
proper function (no inlining), the generated assembler looks good, and the
bug disappears.


Regards,

Jan

--
To UNSUBSCRIBE, email to debian-bugs-...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listm...@lists.debian.org

Ulrich Weigand

unread,
Aug 6, 2010, 9:40:02 AM8/6/10
to
Alexander Sack asked me to look into this.

I can reproduce the problem on Ubuntu maverick, and I fact I get this
compile-time warning that already indicates the problem:
In function 'memset',
inlined from 'g_bsearch_array_create' at /home/uweigand/linaro/glib2.0-2.25.12/glib/gbsearcharray.h:137,
inlined from 'g_signal_init' at /home/uweigand/linaro/glib2.0-2.25.12/gobject/gsignal.c:775:
//usr/include/bits/string3.h:86: warning: call to __builtin___memset_chk will always overflow destination buffer


What's going on here is that everything is inlined into g_signal_init,
and the whole computation of "size" can be done at compile time. This means:

size = sizeof (GBSearchArray) + bconfig->sizeof_node;
if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2)
size = G_BSEARCH_UPPER_POWER2 (size);

gets simplified to

size = sizeof (GBSearchArray) + sizeof (SignalKey);
size = G_BSEARCH_UPPER_POWER2 (size);

which becomes

size = sizeof (GBSearchArray) + sizeof (SignalKey);
size = 1 << g_bit_storage (size - 1);

which in turn is

size = sizeof (GBSearchArray) + sizeof (SignalKey);
size = 1 << (((GLIB_SIZEOF_LONG * 8 - 1) ^ __builtin_clzl (size - 1)) + 1);

Now the problem is that GLIB_SIZEOF_LONG is defined to 8,
even though this is a 32-bit build and sizeof (unsigned long) is 4.

This causes the shift size to be some value greater than 32,
and the result of the shift to be undefined, which happens to
be optimized to 0.

The reason for the wrong GLIB_SIZEOF_LONG seems to be a build issue.
The value is picked up from a file glib2.0-2.25.12/glib/glibconfig.h
which appears to have been generated on a 64-bit machine.

There is also another, apparently correct, version in
glib2.0-2.25.12/debian/build/deb/glib/glibconfig.h
but due to include path ordering, the one in glib/ gets picked up.

Bye,
Ulrich

--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich....@de.ibm.com

0 new messages