Subject: bug#76559: 31.0.50; [-O3 + PGTK] Crash when 'copying as kill'/'killing word'

From: Po Lu <[email-masked]>
Date: Thu, 27 Feb 2025 13:35:17 +0800

Pip Cet <[email-masked]> writes:

> This is strange, but it looks like this may be a C undefined behavior
> bug (or, less likely, an actual GCC bug).  If the event_kind bitfield is
> listed with size 4, shouldn't the hole after it be listed with size 4,
> not size 6?

I'm afraid that must be a Gdb or GCC debuginfo generation bug, since the
total size of the structure is 56.  Whereas the aggregate of the values
printed by GDB is 58.

> Here's the code obtained by disass/s evq_flush which copies the relevant
> part of the header:
>
> 3810	      *kbd_store_ptr = *event;
>    0x00000000002f9f4c <+108>:	movd   %xmm0,(%rdx)
>    0x00000000002f9f50 <+112>:	movdqa 0x20(%rsp),%xmm4
>    0x00000000002f9f56 <+118>:	movdqa 0x10(%rsp),%xmm5
>    0x00000000002f9f5c <+124>:	movq   %xmm1,0x4(%rdx)

If kbd_buffer_store_buffered_event is forcibly inlined, my GCC 12.2.0
generates virtually identical machine code to yours:

   0x000000000067fd8c <+188>:	mov    0x1f653d(%rip),%rdi        # 0x8762d0 <event_q.lto_priv.0>
   0x000000000067fd93 <+195>:	movd   (%rdi),%xmm0
   0x000000000067fd97 <+199>:	movdqu 0x10(%rdi),%xmm2
   0x000000000067fd9c <+204>:	movdqu 0x28(%rdi),%xmm3
   0x000000000067fda1 <+209>:	movq   0x4(%rdi),%xmm1
   0x000000000067fda6 <+214>:	mov    0x20(%rdi),%r14
   0x000000000067fdaa <+218>:	mov    0x38(%rdi),%r13
[...]
   0x000000000067fdb4 <+228>:	movaps %xmm2,0x20(%rsp)
   0x000000000067fdb9 <+233>:	movaps %xmm3,0x10(%rsp)

[...]

   0x000000000067fd27 <+87>:	movd   %xmm0,(%rdx) ;; bytes 0-3
   0x000000000067fd2b <+91>:	movdqa 0x20(%rsp),%xmm4
   0x000000000067fd31 <+97>:	movdqa 0x10(%rsp),%xmm5
   0x000000000067fd37 <+103>:	movq   %xmm1,0x4(%rdx) ;; bytes 4-11
   0x000000000067fd4a <+122>:	mov    %r14,0x20(%rdx) ;; bytes 32-39
   0x000000000067fd4e <+126>:	mov    %r13,0x38(%rdx) ;; bytes 56-63
   0x000000000067fd52 <+130>:	movups %xmm4,0x10(%rdx) ;; bytes 16-31
   0x000000000067fd56 <+134>:	movups %xmm5,0x28(%rdx) ;; bytes 40-55

You'll observe that the gap coincides exactly with the padding in struct
input_event.  This is the RTL GCC produces just as it is lowered from
optimized expression trees:

(insn 582 581 583 62 (set (mem:V2HI (reg/f:DI 106 [ _68 ]) [66 MEM <vector(2) short unsigned int> [(union buffered_input_event *)_68]+0 S4 A32])
        (reg:V2HI 170 [ vect_ev_kind_24.71 ])) "keyboard.c":3810:22 -1
     (nil)) ;; bytes 0-3
(insn 583 582 584 62 (set (mem:V2SI (plus:DI (reg/f:DI 106 [ _68 ])
                (const_int 4 [0x4])) [66 MEM <vector(2) unsigned int> [(union buffered_input_event *)_68 + 4B]+0 S8 A32])
        (reg:V2SI 167 [ vect_ev_ie_code_157.76 ])) "keyboard.c":3810:22 -1
     (nil)) ;; bytes 4-11
(insn 584 583 585 62 (set (mem:V2DI (plus:DI (reg/f:DI 106 [ _68 ])
                (const_int 16 [0x10])) [66 MEM <vector(2) long unsigned int> [(union buffered_input_event *)_68 + 16B]+0 S16 A64])
        (reg:V2DI 164 [ vect_ev_ie_x_134.83 ])) "keyboard.c":3810:22 -1
     (nil)) ;; bytes 16-31
(insn 585 584 586 62 (set (mem:DI (plus:DI (reg/f:DI 106 [ _68 ])
                (const_int 32 [0x20])) [66 MEM <Time> [(union buffered_input_event *)_68 + 32B]+0 S8 A64])
        (reg:DI 84 [ ev$ie$timestamp ])) "keyboard.c":3810:22 -1
     (nil)) ;; bytes 32-39
(insn 586 585 587 62 (set (mem:V2DI (plus:DI (reg/f:DI 106 [ _68 ])
                (const_int 40 [0x28])) [66 MEM <vector(2) long unsigned int> [(union buffered_input_event *)_68 + 40B]+0 S16 A64]) ;; bytes 40-55
        (reg:V2DI 163 [ vect_ev_ie_frame_or_window_11.90 ])) "keyboard.c":3810:22 -1
     (nil))
(insn 587 586 588 62 (set (mem/f:DI (plus:DI (reg/f:DI 106 [ _68 ])
                (const_int 56 [0x38])) [66 MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 56B]+0 S8 A64])
        (reg/f:DI 110 [ ev$ie$device ])) "keyboard.c":3810:22 -1
     (nil)) ;; bytes 56-63

Judging by the expression names, it's clearly copying only the `struct
input_event' union member.  In fact, this erroneous code is generated as
soon as SRA processes aggregate references.

  MEM <short unsigned int> [(union buffered_input_event *)_68] = ev$kind_24;
  MEM <short unsigned int> [(union buffered_input_event *)_68 + 2B] = ev$ie$part_10;
  MEM <unsigned int> [(union buffered_input_event *)_68 + 4B] = ev$ie$code_157;
  MEM <unsigned int> [(union buffered_input_event *)_68 + 8B] = ev$ie$modifiers_58;
  MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 16B] = ev$ie$x_134;
  MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 24B] = ev$ie$y_90;
  MEM <Time> [(union buffered_input_event *)_68 + 32B] = ev$ie$timestamp_23;
  MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 40B] = ev$ie$frame_or_window_11;
  MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 48B] = ev$ie$arg_78;
  MEM <struct Lisp_X *> [(union buffered_input_event *)_68 + 56B] = ev$ie$device_77;

What I suspect is that there is some CU in which `struct
selection_input_event' is incomplete or fails to appear in `union
buffered_input_event' and that that misleads the compiler during
link-time recompilation.  But I could be far off the mark, since I am
very much out of touch with contemporary GCC.