Search code examples
csegmentation-faultsdlsdl-2

c function executes repeatedly without being called, causes segfault


I have been following LazyFoo's SDL2 tutorials and modifying the code slightly so i can compile it as C code on Linux (I am a C programmer and don't know much C++). In the second tutorial he splits his code up into four functions: init() which handles all the initialization, loadMedia() which loads an image, close() which frees all the memory up at the end, and main().

My issue is that partway through the init() function (just after SDL_Init(SDL_INIT_VIDEO) is called), close() is called repeatedly (181 times) before executing the rest of init(). close() then runs a couple more times before the program segfaults.

My modifications to the code are as follows:

  • Changing #include <SDL.h> to #include <SDL2/SDL.h>
  • include <stdbool.h>, as is required by C
  • Changing the file extension to .c from .cpp
  • The addition of a while loop for the rendering portion of the program in main():

    SDL_Event event;
    int quit = false;
    while( !quit ) {
        SDL_WaitEvent( &event );
        if( event.type == SDL_QUIT ) {
            quit = true;
        }
        //Apply the image
        SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
        //Update the surface
        SDL_UpdateWindowSurface( gWindow );
    }
    

    This is to fix an issue I had with the first tutorial where nothing was being drawn to the window

  • Removal of the line SDL_Delay( 2000 ); because it isn't necessary with the rendering loop
  • Changing the path to the .bmp file from 02_getting_an_image_on_the_screen/hello_.bmp to hello.bmp because the source and the image are located in the same folder

I have found that the error occurs even if I remove the call to close(), but runs fine if I remove the function altogether. It also runs fine if I leave the file extension as .cpp, although as far as I'm aware none of the code uses C++ specific features. It might be worth noting that the a window is successfully created, but nothing is ever drawn to it. I'm really at a loss here as to what the cause of it all is.

I compiled the code using GCC V6.3.0 on a Debian Stretch installation. The original source is available for download at the page linked above. My modified version is below.

/*This source code copyrighted by Lazy Foo' Productions (2004-2015)
and may not be redistributed without written permission.*/

//Using SDL and standard IO
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdbool.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//Starts up SDL and creates window
bool init();

//Loads media
bool loadMedia();

//Frees media and shuts down SDL
void close();

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;

//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;

bool init()
{
    //Initialization flag
    bool success = true;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = false;
    }
    else
    {
        //Create window
        gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
        if( gWindow == NULL )
        {
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
            success = false;
        }
        else
        {
            //Get window surface
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }

    return success;
}

bool loadMedia()
{
    //Loading success flag
    bool success = true;

    //Load splash image
    gHelloWorld = SDL_LoadBMP( "hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "hello_world.bmp", SDL_GetError() );
        success = false;
    }

    return success;
}

void close()
{
    //Deallocate surface
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;

    //Destroy window
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;

    //Quit SDL subsystems
    SDL_Quit();
}

int main( int argc, char* args[] )
{
    //Start up SDL and create window
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        //Load media
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            SDL_Event event;
            int quit = false;
            while( !quit ) {
                SDL_WaitEvent( &event );
                if( event.type == SDL_QUIT ) {
                    quit = true;
                }
                //Apply the image
                SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );

                //Update the surface
                SDL_UpdateWindowSurface( gWindow );
            }
        }
    }

    //Free resources and close SDL
    close();

    return 0;
}

Solution

  • close is an operating system function that closes a file handle (an open file, or a socket, or just about anything).

    You have defined your own function called close, and your own functions take priority over library functions. Every time something wants to close a file handle, it calls your close function. (And also the file handle doesn't get closed because the real close function wasn't called).