Subject: Re: bug#12839: 24.3.50; Emacs aborts in GC

From: Dmitry Antipov <[email-masked]>
Date: Fri, 09 Nov 2012 16:44:26 +0400

On 11/09/2012 11:24 AM, Eli Zaretskii wrote:

> Is this what you wanted:
>    (gdb) p Scons
>    $6 = {
>      header = {
>        size = 1241513984
>      },

Yes. The header looks to be valid here
((1241513984 & (0x3f << 24)) >> 24 is 10, e.g. PVEC_SUBR).

> Sorry, I'm not sure I understand: in the first backtrace I've shown,
> which was here (alloc.c:sweep_vectors):
>
> 	      else
> 		{
> 		  int tmp;
> 		  SETUP_ON_FREE_LIST (vector, total_bytes, tmp);  <<<<<<<
> 		}
>
> the vector in question is not a Lisp object, it is a pointer to
> 'struct Lisp_Vector':

I just committed r110854 with pvectype and pvecsize commands, similar
to xvectype and xvecsize; now it should be possible to do something like:

(gdb) p current_buffer
$1 = (struct buffer *) 0xd40ad0
(gdb) pvectype current_buffer
PVEC_BUFFER
(gdb) pvecsize current_buffer
69
48
(gdb) p selected_frame
$2 = {
   i = 19612573
}
(gdb) xvectype
PVEC_FRAME
(gdb) xvecsize
22
47
(gdb)

So, if you see the potentially bogus struct Lisp_Vector pointer, try
pvectype and pvecsize; if you see a bogus Lisp_Object of Lisp_Vectorlike
type, try xvectype and xvecsize.

> I'd be happy to try debugging this myself, but I need guidance
> regarding some basics of what you changed recently in this area.

The goal was to shrink struct vectorlike_header to the only 'size'
field (which is totally overloaded and has the totally misleading
name; someday I would like to switch to bitfields). This means
that we should know the memory footprint of any vectorlike object.
For the regular vector V, the memory footprint is:

header_size + V->header.size * word_size

This is simple because V->header.size is interpreted as follows
(assuming 32-bit code):

31                             0
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mpssssssssssssssssssssssssssssss
|||
||| - s) size bits
|| - p)seudovector bit (always 0)
|- m)ark bit

For the pseudovector V, the layout is:

31                             0
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mpssssssrrrrrrrrrrrrllllllllllll
|||     |           |
|||     |           | l)isp area size, in Lisp_Objects (12 bits) (L)
|||     | r)est area size, in word_size units (12 bits) (R)
||| - s)ubtype (PVEC_xxx, 6 bits)
||- p)seudovector bit (always 1)
|- m)ark bit

(This layout is documented around enum More_Lisp_Bits and
struct vectorlike_header in lisp.h).

So, for the pseudovector V, the memory footprint is:

header_size + (R + L) * word_size

Function vector_nbytes in alloc.c works almost like described
above (with an exception of Lisp_Bool_Vector).

That's why 'pvecsize current_buffer' GDB command prints two numbers.
On a 64-bit system, there are:

(gdb) pvecsize current_buffer
69
48
(gdb)

These are L and R fields, respectively. Since word_size is 8,
header_size + (L + R) * word_size is 8 + (69 + 48) * 8 = 944,
which is equal to sizeof (struct buffer).

The rule above applies to all pseudovector objects except
PVEC_SUBR and PVEC_FREE (but remember that size is rounded up
to multiple of 8 on 32-bit platforms); if it isn't, this is
a bug which is very likely to cause crash with memory corruption
or bogus vector pointers.

Dmitry