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.
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 ()
:
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.
0 comments:
Post a Comment