Search code examples
c++sdl

Subsequent calls to SDL_CreateTextureFromSurface fail with Access Violation when accessing IMG_Load from a member variable


When stepping through the following the debugger encounters a SEGFAULT during the 2nd pass of SDL_CreateTextureFromSurface.

All I have been able to determine is that this may have something to do with pulling IMG_Load from a member variable. When I access IMG_Load directly instead of through a->getSurface() or when I return IMG_Load directly from a->getSurface() then this error doesn't occur.

The following fails:

#include <SDL.h>
#include <SDL_image.h>

class Foo
{
    SDL_Surface* _surface;

public:
    SDL_Surface* getSurface()
    {
        return _surface;
    }

    void setSurface(SDL_Surface* surface)
    {
        _surface = surface;
    }
};

int main()
{
    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    SDL_Window* window = SDL_CreateWindow("foo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    Foo* foo = new Foo();
    foo->setSurface(IMG_Load("img.png"));

    bool quit = false;
    SDL_Event e;

    while(!quit)
    {
        SDL_SetRenderDrawColor(renderer,100,0,0,0);
        SDL_RenderClear(renderer);

        SDL_Surface* surface = foo->getSurface();
        SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

        SDL_RenderCopy(renderer, texture, nullptr, nullptr);

        SDL_FreeSurface(surface);
        SDL_DestroyTexture(texture);

        SDL_RenderPresent(renderer);
        SDL_UpdateWindowSurface(window);

        while(SDL_PollEvent( &e ) != 0)
        {
            if (e.type == SDL_QUIT)
            {
                quit = true;
            }
        }
    }

    delete foo;
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();
    return 0;
}

Changing Foo as follows evades the error:

class Foo
{
public:
    SDL_Surface* getSurface()
    {
        return IMG_Load("img.png");
    }

};

and the following succeeds as well:

SDL_SetRenderDrawColor(renderer,100,0,0,0);
SDL_RenderClear(renderer);

SDL_Surface* surface = IMG_Load("img.png");
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

SDL_RenderCopy(renderer, texture, nullptr, nullptr);

SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);

SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(window);

Solution

  • At the end of first iteration you invoke SDL_FreeSurface(surface); making SDL_Surface* _surface; pointer stored in Foo class instance invalid as well. So on the next iteration SDL_Surface* surface = foo->getSurface(); returns the same invalid pointer causing crash and / or other nasty things associated with Undefined Behavior.