bug in ggc-page?

Daniel Berlin dberlin@dberlin.org
Mon Dec 16 08:25:00 GMT 2002


(I'm not quite sure who originally added the extra_order_size_table, 
and the inverse_table, annotate tells me it's probably one of you three)

In implementing the copying collectors, one of which is based on 
ggc-page, i've run across what appears to be a bug in ggc-page. I'm a 
bit surprised it hasn't been noticed before.

I use the marking bits to track unmovable objects.
In setting the marks on certain ggc allocated things (ggc_allocated_p 
tells me they are ggc allocated, so i'm positive i'm not trying to mark 
non-ggc allocated objects) , we get crashes.

But they only occur if the page is for "order <x>" objects, where x > 
31.

The crash occurs in ggc_set_mark, at

" if (entry->in_use_p[word] & mask)"

(gdb) p word
$10 = 2396745
(gdb) p mask
$11 = 2048
(gdb) p bit
$12 = 76695851

This is, of course, odd.
So i look further at how this is calculated a few lines up:

1073      bit = OFFSET_TO_BIT (((const char *) p) - entry->page, 
entry->order);
1074      word = bit / HOST_BITS_PER_LONG;
1075      mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);


(gdb) p p - entry->page
$13 = 776
(gdb) p entry->bytes
4096
Okeydokey,
Both are reasonable.
(gdb) p entry->order
$14 = 32 ' '
Hmmmm. Looks okay to me.
OFFSET_TO_BIT calculates using the inverse table for the entry's order.
So let's look at that:
(gdb) p inverse_table[32]
$15 = {
   mult = 3067833783,
   shift = 4
}
Uh oh.

Let's look at the whole thing:
gdb) p inverse_table[0]@32+4
$17 = {{
     mult = 1,
     shift = 0
   }, {
     mult = 1,
     shift = 1
   }, {
     mult = 1,
     shift = 2
   }, {
     mult = 1,
     shift = 3
   }, {
     mult = 1,
     shift = 4
   }, {
     mult = 1,
     shift = 5
   }, {
     mult = 1,
     shift = 6
   }, {
     mult = 1,
---Type <return> to continue, or q <return> to quit---
     shift = 7
   }, {
     mult = 1,
     shift = 8
   }, {
     mult = 1,
     shift = 9
   }, {
     mult = 1,
     shift = 10
   }, {
     mult = 1,
     shift = 11
   }, {
     mult = 1,
     shift = 0
   } <repeats 20 times>, {
     mult = 3067833783,
     shift = 4
   }, {
     mult = 3435973837,
     shift = 2
   }, {
     mult = 2863311531,
     shift = 2
   }, {
     mult = 3123612579,
     shift = 2
   }}
(gdb)
(gdb)

Looks like the extra orders have very odd values for mult.
But that's actually not unexpected if one thinks about it.
We do all calculation in unsigned int's, rather than 
HOST_WIDE_UNSIGNED_INT, so the orders > 31 are going to overflow.
Which they do.

Just to be sure it's not corruption, let's recompute the table for the 
extra size orders:

(gdb) p compute_inverse (31)
$24 = void
(gdb) p compute_inverse (32)
$26 = void
(gdb) p compute_inverse (33)
$27 = void
(gdb) p compute_inverse (34)
$28 = void
(gdb)
(gdb) p inverse_table [32]
$23 = {
   mult = 3067833783,
   shift = 4
}

Nope, it's not corrupted.

If i'm right, it means commenting out the extra_order_size_table orders 
should fix the problem.
Which it does.

Comments, thoughts?



More information about the Gcc-bugs mailing list