Deadlock in SDL SIGINT handling

I’ve had an issue with our SDL program where receiving a SIGINT could cause
the program to hang in malloc. This happens when the program receives the
SIGINT while allocating data with malloc on the same thread.

From what I can see, SDL calls malloc from SDL_AddEvent. Because this
happens while already calling malloc on the same thread, a lock in malloc
will be locked two times causing a deadlock.

I’m wondering if this is a bug in SDL (I’ll create a bug report in that
case), or if we are doing something wrong. I guess handling SIGINT
ourselves could solve the problem.

Here’s a backtrace from our program when receiving the SIGINT (in this
trace it happens when freeing):

__lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
95 in …/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
(gdb) where
#0 __lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1 0x00007ffff705395a in _L_lock_12779 () at malloc.c:5206
#2 0x00007ffff7051335 in __GI___libc_malloc (bytes=272) at malloc.c:2887
#3 0x00007ffff7b1c3c2 in SDL_AddEvent (event=0x7fffffffd130) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:205
#4 SDL_PeepEvents_REAL (events=, numevents=,
action=, minType=0, maxType=) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:283
#5 0x00007ffff7b1c6a6 in SDL_PushEvent_REAL (event=event at entry=0x7fffffffd130)
at /build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:471
#6 0x00007ffff7b1ca3b in SDL_SendAppEvent (eventType=SDL_QUIT) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:629
#7
#8 malloc_consolidate (av=av at entry=0x7ffff738d760 <main_arena>) at
malloc.c:4143
#9 0x00007ffff704e0fd in _int_free (av=0x7ffff738d760 <main_arena>,
p=, have_lock=0) at malloc.c:4057

Here’s a simple example to reproduce the problem (SDL 2.0.3, GCC 4.9). Send
a SIGINT while running (might need to try a few times):

const unsigned int numAllocs = 1000;

int main()
{
if (SDL_Init(SDL_INIT_EVENTS) != 0)
{
return 1;
}

int running = 1;

while (running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
running = 0;
}
}

for (unsigned int i = 0; i < numAllocs; i++)
{
int* number = (int*)malloc(sizeof(int));
free(number);
}
}

SDL_Quit();
}

Regards,
Magnus Bjerke Vik

I notice the signal handler calls SDL functions. Are SDL (event) functions
meant to be signal safe? (I doubt it but can’t check at the moment)

Keep in mind that even many libc functions are not signal safe. There’s a
list in a man page somewhere (signal(7) perhaps) of guaranteed safe
functions.

Cheers,
Matt HelsleyOn Feb 5, 2015 1:54 AM, “Magnus Bjerke Vik” wrote:

I’ve had an issue with our SDL program where receiving a SIGINT could
cause the program to hang in malloc. This happens when the program receives
the SIGINT while allocating data with malloc on the same thread.

From what I can see, SDL calls malloc from SDL_AddEvent. Because this
happens while already calling malloc on the same thread, a lock in malloc
will be locked two times causing a deadlock.

I’m wondering if this is a bug in SDL (I’ll create a bug report in that
case), or if we are doing something wrong. I guess handling SIGINT
ourselves could solve the problem.

Here’s a backtrace from our program when receiving the SIGINT (in this
trace it happens when freeing):

__lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
95 in …/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
(gdb) where
#0 __lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1 0x00007ffff705395a in _L_lock_12779 () at malloc.c:5206
#2 0x00007ffff7051335 in __GI___libc_malloc (bytes=272) at malloc.c:2887
#3 0x00007ffff7b1c3c2 in SDL_AddEvent (event=0x7fffffffd130) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:205
#4 SDL_PeepEvents_REAL (events=, numevents=, action=, minType=0, maxType=) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:283
#5 0x00007ffff7b1c6a6 in SDL_PushEvent_REAL (event=event at entry=0x7fffffffd130)
at /build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:471
#6 0x00007ffff7b1ca3b in SDL_SendAppEvent (eventType=SDL_QUIT) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:629
#7
#8 malloc_consolidate (av=av at entry=0x7ffff738d760 <main_arena>) at
malloc.c:4143
#9 0x00007ffff704e0fd in _int_free (av=0x7ffff738d760 <main_arena>,
p=, have_lock=0) at malloc.c:4057

Here’s a simple example to reproduce the problem (SDL 2.0.3, GCC 4.9).
Send a SIGINT while running (might need to try a few times):

const unsigned int numAllocs = 1000;

int main()
{
if (SDL_Init(SDL_INIT_EVENTS) != 0)
{
return 1;
}

int running = 1;

while (running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
running = 0;
}
}

for (unsigned int i = 0; i < numAllocs; i++)
{
int* number = (int*)malloc(sizeof(int));
free(number);
}
}

SDL_Quit();
}

Regards,
Magnus Bjerke Vik


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Go ahead and report this as a bug. It makes sense that making an allocation
inside malloc routines would be a bad idea. I’m not sure how we fix that
yet.

Thanks for the report!On Thu, Feb 5, 2015 at 1:54 AM, Magnus Bjerke Vik wrote:

I’ve had an issue with our SDL program where receiving a SIGINT could
cause the program to hang in malloc. This happens when the program receives
the SIGINT while allocating data with malloc on the same thread.

From what I can see, SDL calls malloc from SDL_AddEvent. Because this
happens while already calling malloc on the same thread, a lock in malloc
will be locked two times causing a deadlock.

I’m wondering if this is a bug in SDL (I’ll create a bug report in that
case), or if we are doing something wrong. I guess handling SIGINT
ourselves could solve the problem.

Here’s a backtrace from our program when receiving the SIGINT (in this
trace it happens when freeing):

__lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
95 in …/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
(gdb) where
#0 __lll_lock_wait_private () at
…/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1 0x00007ffff705395a in _L_lock_12779 () at malloc.c:5206
#2 0x00007ffff7051335 in __GI___libc_malloc (bytes=272) at malloc.c:2887
#3 0x00007ffff7b1c3c2 in SDL_AddEvent (event=0x7fffffffd130) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:205
#4 SDL_PeepEvents_REAL (events=, numevents=, action=, minType=0, maxType=) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:283
#5 0x00007ffff7b1c6a6 in SDL_PushEvent_REAL (event=event at entry=0x7fffffffd130)
at /build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:471
#6 0x00007ffff7b1ca3b in SDL_SendAppEvent (eventType=SDL_QUIT) at
/build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_events.c:629
#7
#8 malloc_consolidate (av=av at entry=0x7ffff738d760 <main_arena>) at
malloc.c:4143
#9 0x00007ffff704e0fd in _int_free (av=0x7ffff738d760 <main_arena>,
p=, have_lock=0) at malloc.c:4057

Here’s a simple example to reproduce the problem (SDL 2.0.3, GCC 4.9).
Send a SIGINT while running (might need to try a few times):

const unsigned int numAllocs = 1000;

int main()
{
if (SDL_Init(SDL_INIT_EVENTS) != 0)
{
return 1;
}

int running = 1;

while (running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
running = 0;
}
}

for (unsigned int i = 0; i < numAllocs; i++)
{
int* number = (int*)malloc(sizeof(int));
free(number);
}
}

SDL_Quit();
}

Regards,
Magnus Bjerke Vik


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

No problem. The bug report: https://bugzilla.libsdl.org/show_bug.cgi?id=2870

Also, our bug report:

  • MagnusOn Fri, Feb 6, 2015 at 2:08 PM, Sam Lantinga wrote:

Go ahead and report this as a bug. It makes sense that making an allocation
inside malloc routines would be a bad idea. I’m not sure how we fix that
yet.

Thanks for the report!