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

From: Pip Cet <[email-masked]>
Date: Wed, 26 Feb 2025 20:24:14 +0000

Pip Cet <[email-masked]> writes:

> "Iurie Marian" <[email-masked]> writes:
>
>> Yes, it looks like Michael's changes have nothing to do with this bug,
>> but these seem just to reveal some undefined behavior... idk. Btw, 
>> just by commenting the line src/keyboard.c:11697, it is not crashing 
>> anymore; maybe this could be a hint.
>>
>>> gcc --version
>> gcc (Debian 12.2.0-14) 12.2.0
>>
>>> Can you check that 0x555555cf0b00 is a valid dpyinfo structure?
>> (gdb) info locals
>> event = 0x555555953aa0 <kbd_buffer+384>
>> copy = {kind = SELECTION_REQUEST_EVENT, dpyinfo = 0x55c82260, requestor = 0x555555f93a80, selection = 0x45, target = 0x4d, property =
>> 0x5e, time = 0}
>> moved_events = <optimized out>
>>
>> (gdb) x 0x555555c82260
>> 0x555555c82260: 0x00
>
> Well, that only tells us the first byte is 0, which is probably correct.
> Can you retry with x/64gx 0x555555c82260 (or the new address) so we see
> some more data?
>
>>> Can you run "ptype/o struct selection_input_event" [...]
>>
>> (gdb) ptype/o struct selection_input_event
>> /* offset      |    size */  type = struct selection_input_event {
>> /*      0: 0   |       4 */    enum event_kind kind : 16;
>> /* XXX  6-byte hole      */
>
> 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?

Investigating the undefined behavior bug theory further, I find that
applying this patch changes the code emitted for evq_flush (I think this
is strange, since evq_flush doesn't call kbd_buffer_store_event, it
calls kbd_buffer_store_buffered_event!).

diff --git a/src/keyboard.h b/src/keyboard.h
index 5e04b54eb74..c1c75cc7ea5 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -505,10 +505,9 @@ #define EVENT_HEAD_KIND(event_head) \
 kbd_buffer_store_event_hold (struct input_event *event,
 			     struct input_event *hold_quit)
 {
-  static_assert (alignof (struct input_event) == alignof (union buffered_input_event)
-		 && sizeof (struct input_event) == sizeof (union buffered_input_event));
-  kbd_buffer_store_buffered_event ((union buffered_input_event *) event,
-				   hold_quit);
+  union buffered_input_event bie;
+  bie.ie = *event;
+  kbd_buffer_store_buffered_event (&bie, hold_quit);
 }
 extern void poll_for_input_1 (void);
 extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object,

Can you confirm whether it changes anything for you?

Pip