[SDL 3.1.6] Memory leeks

I tested the following program, which is actually nothing special.

I tested it with valgrind --leak-check=full ./main. Why am I getting so many errors?

/*
  Linux:
  gcc main.c -o main -lSDL3

  Windows:
  x86_64-w64-mingw32-gcc main.c -o main.exe -lSDL3 -I/usr/local/include -L/usr/local/bin
*/

#include <SDL3/SDL.h>

int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);   
    SDL_Window *window = SDL_CreateWindow("An SDL3 window",  640, 480, SDL_WINDOW_OPENGL);
    SDL_Delay(3000);  
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

Output:

$ valgrind --leak-check=full ./main 
==2878== Memcheck, a memory error detector
==2878== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==2878== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==2878== Command: ./main
==2878== 
==2878== 
==2878== HEAP SUMMARY:
==2878==     in use at exit: 350,549 bytes in 3,376 blocks
==2878==   total heap usage: 24,139 allocs, 20,763 frees, 6,086,239 bytes allocated
==2878== 
==2878== 29 bytes in 1 blocks are definitely lost in loss record 158 of 2,366
==2878==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5374F93: ???
==2878==    by 0x535AAE7: ???
==2878==    by 0x4B27296: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x1091E5: main (in /n4800/DATEN/Programmierung/mit_GIT/Lazarus/Tutorial/SDL-3/Versuche/C/native_C/SDL3_CreateWindow/main)
==2878== 
==2878== 29 bytes in 1 blocks are definitely lost in loss record 159 of 2,366
==2878==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5374F93: ???
==2878==    by 0x535AAAA: ???
==2878==    by 0x4B27296: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x1091E5: main (in /n4800/DATEN/Programmierung/mit_GIT/Lazarus/Tutorial/SDL-3/Versuche/C/native_C/SDL3_CreateWindow/main)
==2878== 
==2878== 38 bytes in 1 blocks are definitely lost in loss record 946 of 2,366
==2878==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5374F93: ???
==2878==    by 0x535A8D9: ???
==2878==    by 0x4B27296: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x1091E5: main (in /n4800/DATEN/Programmierung/mit_GIT/Lazarus/Tutorial/SDL-3/Versuche/C/native_C/SDL3_CreateWindow/main)
==2878== 
==2878== 72 (24 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 2,302 of 2,366
==2878==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x537CD95: ???
==2878==    by 0x5367A45: ???
==2878==    by 0x536CD6E: ???
==2878==    by 0x535A1B2: ???
==2878==    by 0x535A43B: ???
==2878==    by 0x535A707: ???
==2878==    by 0x4B27296: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878== 
==2878== 520 bytes in 13 blocks are definitely lost in loss record 2,337 of 2,366
==2878==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5378C8B: ???
==2878==    by 0x536C934: ???
==2878==    by 0x4B27269: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x1091E5: main (in /n4800/DATEN/Programmierung/mit_GIT/Lazarus/Tutorial/SDL-3/Versuche/C/native_C/SDL3_CreateWindow/main)
==2878== 
==2878== 727 (184 direct, 543 indirect) bytes in 1 blocks are definitely lost in loss record 2,341 of 2,366
==2878==    at 0x484D953: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5366DDF: ???
==2878==    by 0x5367BF4: ???
==2878==    by 0x535A41C: ???
==2878==    by 0x535A707: ???
==2878==    by 0x4B27296: SDL_DBus_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B26D7: SDL_InitSubSystem_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48B2A2E: SDL_Init_REAL (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48E1160: SDL_Init_DEFAULT (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x48EE940: SDL_Init (in /usr/local/lib/libSDL3.so.0.1.7)
==2878==    by 0x1091E5: main (in /n4800/DATEN/Programmierung/mit_GIT/Lazarus/Tutorial/SDL-3/Versuche/C/native_C/SDL3_CreateWindow/main)
==2878== 
==2878== 2,302 (736 direct, 1,566 indirect) bytes in 4 blocks are definitely lost in loss record 2,354 of 2,366
==2878==    at 0x484D953: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2878==    by 0x5366DDF: ???
==2878==    by 0x5368D6D: ???
==2878==    by 0x53718DB: ???
==2878==    by 0x5371AAF: ???
==2878==    by 0x5372BE0: ???
==2878==    by 0x53731CF: ???
==2878==    by 0x5358391: ???
==2878==    by 0x536D04C: ???
==2878==    by 0x535A19D: ???
==2878==    by 0x535A43B: ???
==2878==    by 0x535A707: ???
==2878== 
==2878== LEAK SUMMARY:
==2878==    definitely lost: 1,560 bytes in 22 blocks
==2878==    indirectly lost: 2,157 bytes in 12 blocks
==2878==      possibly lost: 0 bytes in 0 blocks
==2878==    still reachable: 346,832 bytes in 3,342 blocks
==2878==         suppressed: 0 bytes in 0 blocks
==2878== Reachable blocks (those to which a pointer was found) are not shown.
==2878== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==2878== 
==2878== For lists of detected and suppressed errors, rerun with: -s
==2878== ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0)

We leave D-bus active so that your program doesn’t crash if other parts of your application are still using it after SDL_Quit().

You can do a full D-bus cleanup by calling:

SDL_SetHint(SDL_HINT_SHUTDOWN_DBUS_ON_QUIT, "1");

or setting the environment variable SDL_SHUTDOWN_DBUS_ON_QUIT=1

3 Likes

Now the memory leak is gone. Thanks.
I had to rewrite Set(h)int.

int main(int argc, char* argv[]) {
  SDL_SetHint(SDL_HINT_SHUTDOWN_DBUS_ON_QUIT, "1");
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Window *window = SDL_CreateWindow("An SDL3 window", 640, 480, SDL_WINDOW_OPENGL);
  SDL_Delay(3000);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}
1 Like

I compiled the user’s example, and initially, Valgrind reported 10 memory leaks. After adding the following line to the code, the number of leaks was reduced to two. What else can I do to completely eliminate these remaining leaks related to SDL_DBus_Init?

==4724== Memcheck, a memory error detector
==4724== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==4724== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==4724== Command: ./main
==4724== 
==4724== 
==4724== HEAP SUMMARY:
==4724==     in use at exit: 355,621 bytes in 3,398 blocks
==4724==   total heap usage: 24,659 allocs, 21,261 frees, 5,903,086 bytes allocated
==4724== 
==4724== 8 bytes in 1 blocks are definitely lost in loss record 11 of 2,399
==4724==    at 0x484DB80: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4724==    by 0x53695C1: ???
==4724==    by 0x5352D8C: ???
==4724==    by 0x5356390: ???
==4724==    by 0x5356707: ???
==4724==    by 0x4B0ADFE: SDL_DBus_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x489076C: SDL_InitSubSystem_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x4890ACF: SDL_Init_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x48CCCC7: SDL_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x10921E: main (in /home/harbour/Dokumenty/hbsdl3/tests/main)
==4724== 
==4724== 8,765 (40 direct, 8,725 indirect) bytes in 1 blocks are definitely lost in loss record 2,395 of 2,399
==4724==    at 0x484D953: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==4724==    by 0x53713B9: ???
==4724==    by 0x5378456: ???
==4724==    by 0x53784D7: ???
==4724==    by 0x5378544: ???
==4724==    by 0x534DC68: ???
==4724==    by 0x535522D: ???
==4724==    by 0x53566F0: ???
==4724==    by 0x4B0ADFE: SDL_DBus_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x489076C: SDL_InitSubSystem_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x4890ACF: SDL_Init_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724==    by 0x48CCCC7: SDL_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==4724== 
==4724== LEAK SUMMARY:
==4724==    definitely lost: 48 bytes in 2 blocks
==4724==    indirectly lost: 8,725 bytes in 54 blocks
==4724==      possibly lost: 0 bytes in 0 blocks
==4724==    still reachable: 346,848 bytes in 3,342 blocks
==4724==         suppressed: 0 bytes in 0 blocks
==4724== Reachable blocks (those to which a pointer was found) are not shown.
==4724== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==4724== 
==4724== For lists of detected and suppressed errors, rerun with: -s
==4724== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

First leak:

  • 8 bytes in 1 block.
  • The call originates from the realloc function and ultimately from SDL_DBus_Init.
  • Label: “definitely lost” (definitely lost).

Second leak:

  • 8,765 bytes (40 bytes “directly lost” and 8,725 bytes “indirectly lost”).
  • The call originates from the calloc function in SDL_DBus_Init.
  • Label: “definitely lost” (definitely lost).

Sorry, I forgot to add that for Version: 3.1.7.

I’m not sure, can you get the libdbus symbols so we can get a full stack trace inside that library?

Below is the relevant part of the output showing memory leaks in SDL_DBus_Init within libSDL3.so. The symbols are now available, and it seems the issue is related to how SDL_DBus_Init handles memory.

==52659== 
==52659== HEAP SUMMARY:
==52659==     in use at exit: 355,623 bytes in 3,398 blocks
==52659==   total heap usage: 24,659 allocs, 21,261 frees, 5,903,100 bytes allocated
==52659== 
==52659== 8 bytes in 1 blocks are definitely lost in loss record 11 of 2,399
==52659==    at 0x484DB80: realloc (vg_replace_malloc.c:1690)
==52659==    by 0x536A5C1: ???
==52659==    by 0x5353D8C: ???
==52659==    by 0x5357390: ???
==52659==    by 0x5357707: ???
==52659==    by 0x4B0B5E3: SDL_DBus_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x489076C: SDL_InitSubSystem_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x4890ACF: SDL_Init_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x48CCD4C: SDL_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x10921E: main (in /home/harbour/Dokumenty/hbsdl3/tests/main)
==52659== 
==52659== 8,767 (40 direct, 8,727 indirect) bytes in 1 blocks are definitely lost in loss record 2,395 of 2,399
==52659==    at 0x484D953: calloc (vg_replace_malloc.c:1595)
==52659==    by 0x53723B9: ???
==52659==    by 0x5379456: ???
==52659==    by 0x53794D7: ???
==52659==    by 0x5379544: ???
==52659==    by 0x534EC68: ???
==52659==    by 0x535622D: ???
==52659==    by 0x53576F0: ???
==52659==    by 0x4B0B5E3: SDL_DBus_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x489076C: SDL_InitSubSystem_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x4890ACF: SDL_Init_REAL (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659==    by 0x48CCD4C: SDL_Init (in /home/harbour/SDL/build/libSDL3.so.0.1.7)
==52659== 
==52659== LEAK SUMMARY:
==52659==    definitely lost: 48 bytes in 2 blocks
==52659==    indirectly lost: 8,727 bytes in 54 blocks
==52659==      possibly lost: 0 bytes in 0 blocks
==52659==    still reachable: 346,848 bytes in 3,342 blocks
==52659==         suppressed: 0 bytes in 0 blocks
==52659== Reachable blocks (those to which a pointer was found) are not shown.
==52659== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==52659== 
==52659== For lists of detected and suppressed errors, rerun with: -s
==52659== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

I manually tested SDL_DBus_Quit, and it didn’t show any issues during cleanup.

void SDL_DBus_Quit(void)
{
    if (!SDL_ShouldQuit(&dbus_init)) {
        return;
    }

    if (inhibit_handle) {
        SDL_Log("Freeing inhibit_handle: %s", inhibit_handle);
        if (!SDL_DBus_CallVoidMethod("org.freedesktop.portal.Desktop", inhibit_handle, "org.freedesktop.portal.Request", "Close", DBUS_TYPE_INVALID)) {
            SDL_Log("Failed to close inhibit handle for: %s", inhibit_handle);
        } else {
            SDL_Log("Successfully closed inhibit handle: %s", inhibit_handle);
        }
        SDL_free(inhibit_handle);
        inhibit_handle = NULL;
    }

    if (dbus.system_conn) {
        SDL_Log("Closing system connection: %p", dbus.system_conn);
        if (!dbus.connection_get_is_connected(dbus.system_conn)) {
            SDL_Log("System connection is already closed");
        } else {
            dbus.connection_close(dbus.system_conn); 
            dbus.connection_unref(dbus.system_conn); 
            SDL_Log("System connection successfully closed");
        }
        dbus.system_conn = NULL;
    }

    if (dbus.session_conn) {
        SDL_Log("Closing session connection: %p", dbus.session_conn);
        if (!dbus.connection_get_is_connected(dbus.session_conn)) {
            SDL_Log("Session connection is already closed");
        } else {
            dbus.connection_close(dbus.session_conn);
            dbus.connection_unref(dbus.session_conn);
            SDL_Log("Session connection successfully closed");
        }
        dbus.session_conn = NULL;
    }

    if (SDL_GetHintBoolean(SDL_HINT_SHUTDOWN_DBUS_ON_QUIT, false) && dbus.shutdown) {
        SDL_Log("Calling dbus.shutdown");
        dbus.shutdown();
        SDL_Log("DBus shutdown completed");
    }

    SDL_zero(dbus);

    if (dbus_handle) {
        SDL_Log("Unloading DBus library: %p", dbus_handle);
        SDL_UnloadObject(dbus_handle);
        dbus_handle = NULL;
        SDL_Log("DBus library unloaded");
    }

    SDL_SetInitialized(&dbus_init, false);
}

Despite this, the memory leak indicated by Valgrind still seems to occur during SDL_DBus_Init. Could this be related to allocations not covered in SDL_DBus_Quit?