libSDL failing to initialize with `double free` error

I’m using Debian Testing and these are the installed packages:

|libsdl2-2.0-0:amd64||2.0.10+dfsg1-3|
|---|---|---|
|libsdl2-2.0-0:i386||2.0.10+dfsg1-3|
|libsdl2-dev:amd64||2.0.10+dfsg1-3|
|libsdl2-gfx-1.0-0:amd64||1.0.4+dfsg-3+b1|
|libsdl2-gfx-dev:amd64||1.0.4+dfsg-3+b1|
|libsdl2-image-2.0-0:amd64||2.0.5+dfsg1-2|
|libsdl2-image-dev:amd64||2.0.5+dfsg1-2|
|libsdl2-mixer-2.0-0:amd64||2.0.4+dfsg1-2+b1|
|libsdl2-mixer-dev:amd64||2.0.4+dfsg1-2+b1|
|libsdl2-net-2.0-0:amd64||2.0.1+dfsg1-4+b1|
|libsdl2-net-dev:amd64||2.0.1+dfsg1-4+b1|
|libsdl2-ttf-2.0-0:amd64||2.0.15+dfsg1-1|
|libsdl2-ttf-dev:amd64||2.0.15+dfsg1-1|

Trying to compile and run a small Hello World like code (from lazyfoo’s)

#include <SDL2/SDL.h>

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

void init();
void loadMedia();
void close();

SDL_Window * gWindow = NULL;
SDL_Surface * gScreenSurface = NULL;
SDL_Surface * gHelloWorld = NULL;

void
init_interface() {

    SDL_Init(SDL_INIT_VIDEO);
    gWindow = SDL_CreateWindow("Fractal", 
                SDL_WINDOWPOS_UNDEFINED,
                SDL_WINDOWPOS_UNDEFINED,
                SCREEN_WIDTH,
                SCREEN_HEIGHT,
                SDL_WINDOW_SHOWN);
    gScreenSurface = SDL_GetWindowSurface(gWindow);
}

void loadMedia()
{
    gHelloWorld = SDL_LoadBMP("hello.bmp");
}

void close()
{
    SDL_FreeSurface(gHelloWorld);
    SDL_DestroyWindow(gWindow);
    SDL_Quit();
}


int main(int argc, char *argv[]) { 
    init_interface();
    loadMedia();
    SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);
    SDL_UpdateWindowSurface(gWindow);

    SDL_Delay(20000);
    close();
    return 0;
}

Returns the error:

free(): double free detected in tcache 2
Aborted

Changing the code to a simpler version (not using globals or function calls)

#include <SDL2/SDL.h>

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

int main(int argc, char *argv[]) { 
    SDL_Window * gWindow = NULL;
    SDL_Surface * gScreenSurface = NULL;
    SDL_Surface * gHelloWorld = NULL;
    SDL_Init(SDL_INIT_VIDEO);
    gWindow = SDL_CreateWindow("Fractal", 
                SDL_WINDOWPOS_UNDEFINED,
                SDL_WINDOWPOS_UNDEFINED,
                SCREEN_WIDTH,
                SCREEN_HEIGHT,
                SDL_WINDOW_SHOWN);
    gScreenSurface = SDL_GetWindowSurface(gWindow);
    gHelloWorld = SDL_LoadBMP("hello.bmp");
    SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);
    SDL_UpdateWindowSurface(gWindow);
    SDL_Delay(2000);
    SDL_FreeSurface(gHelloWorld);
    SDL_DestroyWindow(gWindow);
    SDL_Quit();
    return 0;
}

Works fine. What is wrong with original code?

1 Like

Hi,

I am new to SDL but I guess you should not free the surface (gScreenSurface) because the surface is owned by the Window. For example, in a similar sample, the surface is not explicitly freed:

https://wiki.libsdl.org/SDL_GetWindowSurface

1 Like

Hello. Thank you for your reply.

I do not free the gScreenSurface, but I do for gHelloWorld.

Ok. I looked closely and the LoadBMP over a png file is wrong I guessand the call returns a NULL surface on my system.

Not that too. Even fixing for a valid BMP. it wont work. If it would return NULL it would be triggered in tthe next if condition. That do not happen.

Also the code without globals and functions even with the .png works. It just don’t display anything.

Anyhow I will fix the .bmp there to avoid further misleading.

It also seems wrong to me and error prone to me to use a window without looping over the events. I mean, you are closing the window when it is in a sort of undefined state because no events were processed at all.

There is no need to process any events to display a window (or close it). Also, if that was the case, the code without globals and functions should also not work.

Not everything is clear for me but the code here works (taken from

https://wiki.libsdl.org/SDL_GetWindowSurface

):

#include <unistd.h>
#include "SDL.h" // include SDL header

int main(int argc, char* argv[])
{
    SDL_Surface *screen; // even with SDL2, we can still bring ancient code back
    SDL_Window *window;
    SDL_Surface *image;

    SDL_Init(SDL_INIT_VIDEO); // init video

    // create the window like normal
    window = SDL_CreateWindow("SDL2 Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

    // but instead of creating a renderer, we can draw directly to the screen
    screen = SDL_GetWindowSurface(window);

    // let's just show some classic code for reference
    image = SDL_LoadBMP("hello.bmp"); // loads image
    SDL_BlitSurface(image, NULL, screen, NULL); // blit it to the screen
    SDL_FreeSurface(image);

    // this works just like SDL_Flip() in SDL 1.2
    SDL_UpdateWindowSurface(window);

    sleep(4);

    // show image for 2 seconds
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

So you are right, no need to process the events. The thing I notice is:

  1. SDL_Delay doesn’t seem to work on my Linux 32bit x86 system! Replaced with old good sleep.
  2. A call to SDL_UpdateWindowSurface is needed.

SDL_Delay works in (ms) while sleep works in seconds. Your code is exactly like mine withoutt functions and globals. that works as I have stated before.

Yes. a call to SDL_UpdateWindowSurface the window is needed to refresh screen buffer the drawn but that isn’t issue here.

I will also add tthe call to SDL_UpdateWindowSurface in original pos tto avoid further misleading.

I came to this topic hoping that it would tell me the answer I need, but instead I think I figured out the OP’s problem (and mine).

First some background. This code comes from the “Lazy Foo” tutorial on SDL2, and that tutorial uses C++. However, as a programmer that prefers C, I thought I might still be able to learn from it, and since at least in the first few tutorials, it’s almost entirely C anyway I thought this might work. But then tutorial 2 had me stumped for a couple of hours. After changing “bool” to "int’ (and #define’ing “true” and “false”), the code was pure-C, and so I compiled it, but got the same error as the OP:

% ./02_getting_an_image_on_the_screen
free(): double free detected in tcache 2
Aborted (core dumped)

As with the OP, I tried moving things around in the code, and eventually was able to get it to compile and run using gcc (and clang). So I narrowed things down until I found what I think the problem is.

The tutorial creates a function called – close()

But guess what, stdio also has a function called close(). And renaming close() to "MyClose() or something fixes the problem! So very very likely what’s happening is that one of the SDL initialization calls opens a file I/O and then calls “close()” when done. But instead of calling the sdtio’s close, it calls the one in the tutorial and thus closes out the initialized SDL system.

So chalk this up as a win for C++, and in particular namespaces. (But I still prefer C.)

1 Like

A funny thing happened on my way back from the discussion forum. I read the step-by-step explanation by Lazy Foo on the tutorial page, and the problem with the close() function in C is acknowledged right there. So I guess I should have read the text first! But it confirms my conclusion.