Saturday, August 26, 2017

Calling SDL “IMG_Load” a second time results in a “EXC_BAD_ACCESS (code=EXC_I386_GPFLT)”

Leave a Comment

Im running this on MacOS 10.12 using Xcode 8.3.3 with SDL2 installed via Homebrew as Dylibs.

Below is some slightly modified sample code from lazy foo.

I just added a second texture gTexture2 and the function loadMedia2 to be able to reproduce the issue. The second time IMG_Load is executed it crashes with the following message:

EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 

Searching on how to solve a "General Protection Fault" problem did also not get me further, the crash seems to happen inside SDL. I probably really misunderstand here something that leads to this issue and would really welcome any help.

enter image description here

The really confusing thing is, it does not crash always, only about 2 of 3 times.

The crash seem to happen inside SDL_AllocFormat_REAL ():

enter image description here

Here is the code sample.

/*This source code copyrighted by Lazy Foo' Productions (2004-2015)  and may not be redistributed without written permission.*/  //Using SDL, SDL_image, standard IO, and strings #include <SDL.h> #include <SDL_image.h> #include <stdio.h> #include <string>  //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();  //Loads individual image as texture SDL_Texture* loadTexture( std::string path );  //The window we'll be rendering to SDL_Window* gWindow = NULL;  //The window renderer SDL_Renderer* gRenderer = NULL;  //Current displayed texture SDL_Texture* gTexture = NULL; SDL_Texture* gTexture2 = 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     {         //Set texture filtering to linear         if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )         {             printf( "Warning: Linear texture filtering not enabled!" );         }          //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         {             //Create renderer for window             gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );             if( gRenderer == NULL )             {                 printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );                 success = false;             }             else             {                 //Initialize renderer color                 SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );                  //Initialize PNG loading                 int imgFlags = IMG_INIT_PNG;                 if( !( IMG_Init( imgFlags ) & imgFlags ) )                 {                     printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );                     success = false;                 }             }         }     }      return success; }  bool loadMedia() {     //Loading success flag     bool success = true;      //Load PNG texture     gTexture = loadTexture( "../assets/player.png" );     if( gTexture == NULL )     {         printf( "Failed to load texture image!\n" );         success = false;     }      return success; }  bool loadMedia2() {     //Loading success flag     bool success = true;      //Load PNG texture     gTexture2 = loadTexture( "../assets/scene_main/background.png" );     if( gTexture == NULL )     {         printf( "Failed to load texture image!\n" );         success = false;     }      return success; }  void close() {     //Free loaded image     SDL_DestroyTexture( gTexture );     SDL_DestroyTexture( gTexture2 );     gTexture = NULL;     gTexture2 = NULL;              //Destroy window     SDL_DestroyRenderer( gRenderer );     SDL_DestroyWindow( gWindow );     gWindow = NULL;     gRenderer = NULL;      //Quit SDL subsystems     IMG_Quit();     SDL_Quit(); }  SDL_Texture* loadTexture( std::string path ) {     //The final texture     SDL_Texture* newTexture = NULL;      //Load image at specified path     SDL_Surface* loadedSurface = IMG_Load( path.c_str() );     if( loadedSurface == NULL )     {         printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );     }     else     {         //Create texture from surface pixels         newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );         if( newTexture == NULL )         {             printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );         }          //Get rid of old loaded surface         SDL_FreeSurface( loadedSurface );     }      return newTexture; }  int main( int argc, char* args[] ) {     //Start up SDL and create window     if( !init() )     {         printf( "Failed to initialize!\n" );     }     else     {         //Load media         if( !loadMedia() || !loadMedia2() )         {             printf( "Failed to load media!\n" );         }         else         {                //Main loop flag             bool quit = false;              //Event handler             SDL_Event e;              //While application is running             while( !quit )             {                 //Handle events on queue                 while( SDL_PollEvent( &e ) != 0 )                 {                     //User requests quit                     if( e.type == SDL_QUIT )                     {                         quit = true;                     }                 }                  //Clear screen                 SDL_RenderClear( gRenderer );                  //Render texture to screen                 SDL_RenderCopy( gRenderer, gTexture, NULL, NULL );                  //Update screen                 SDL_RenderPresent( gRenderer );             }         }     }      //Free resources and close SDL     close();      return 0; }    

Little Update:

  • I've tried it on windows, there it runs completely fine. So I guess the issue is related to MacOs.

  • I already tried to reinstall all libraries.

  • I'm using C++14.

The solution

Thanks to @Sahib Yar he pointed out to try to put the images in the same directory. Which resolves the issue.

Now I would really love an explanation why we can't load images from multiple directories using SDL on MacOS. Is that just a bug or known thing.

1 Answers

Answers 1

It seems that you are not destroying texture2 that is not needed.

SDL_DestroyTexture( gTexture ); SDL_DestroyTexture( gTexture2 );  gTexture = NULL; gTexture2 = NULL; 

In this lazyfoo tutorial, it is mentioned that

In our clean up function, we have to remember to deallocate our textures using SDL_DestroyTexture.

Edit 1:

Try to put all your images in the same directory.

Edit 2:

It is not related to directory in MacOS From this tutorial, it seems like compiler is doing some optimization with std::string path as the std::string is mutable. Try to clear the std::string path object at end of function to clear up all the memory reserved by its objects.

add this line.

std::string().swap(path); 

Your issue is a dangling pointer. EXC_BAD_ACCESS is the CPU moaning that you are addressing non-existent memory or memory which is outside of your access rights area. The cause is a lack of reatainment of an object which causes early deallocation and then is overwritten. At which time (which may be delayed), the pointer will point to garbage whose dereference causes an EXC_BAD_ACCESS to be thrown.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment