I've disassembled the offending library code and looking at the register dump we can learn a little more....
Firstly, I now think the problem is *not* in ply_event_loop_process_pending_events() - it's in ply_event_loop_handle_timeouts(). The reason for the confusion is that it appears that gcc has optimized ply_event_loop_handle_timeouts() by inlining it into ply_event_loop_process_pending_events(). So, if we now look at ply_event_loop_handle_timeouts(), we can see the code that's causing plymouthd to die:
The offending line is 1224. In assembler this equates to:
test %ecx,0x4(%esi)
... where ecx=0x1 and esi = 0x0.
In pseudo-C-code though what is actually happening in plymouthd is:
if ( NULL->timeout <= 1)
So the problem is that the timeout watch is NULL. Looking at the C code shows that no check is performed on 'watch' being NULL or not - it's just blindly dereferenced which causes the SIGSEGV. However, I can't yet see how watch is ever NULL, unless it's that pesky alloca causing undefined behaviour maybe.
I've disassembled the offending library code and looking at the register dump we can learn a little more....
Firstly, I now think the problem is *not* in ply_event_ loop_process_ pending_ events( ) - it's in ply_event_ loop_handle_ timeouts( ). The reason for the confusion is that it appears that gcc has optimized ply_event_ loop_handle_ timeouts( ) by inlining it into ply_event_ loop_process_ pending_ events( ). So, if we now look at ply_event_ loop_handle_ timeouts( ), we can see the code that's causing plymouthd to die:
1216 while (node != NULL) loop_timeout_ watch_t *watch; loop_timeout_ watch_t *) ply_list_ node_get_ data (node); get_next_ node (loop-> timeout_ watches, node);
1217 {
1218 ply_list_node_t *next_node;
1219 ply_event_
1220
1221 watch = (ply_event_
1222 next_node = ply_list_
1223
1224 if (watch->timeout <= now) /* XXX: crash is triggered here */
1225 {
The offending line is 1224. In assembler this equates to:
test %ecx,0x4(%esi)
... where ecx=0x1 and esi = 0x0.
In pseudo-C-code though what is actually happening in plymouthd is:
if ( NULL->timeout <= 1)
So the problem is that the timeout watch is NULL. Looking at the C code shows that no check is performed on 'watch' being NULL or not - it's just blindly dereferenced which causes the SIGSEGV. However, I can't yet see how watch is ever NULL, unless it's that pesky alloca causing undefined behaviour maybe.