C/SDL – Segmentation fault when program run multiple times in succession [closed]

Let me break down a debugging session for you, but in future you better do that yourself.

If the problem can be easily reproduced, it is quite trivial to fix it:

gdb ./GAME
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b2d10c in ?? () from /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
(gdb) bt
#0  0x00007ffff7b2d10c in ?? () from /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
#1  0x000000000040650c in sprite_free_age ()
#2  0x00000000004065f9 in AGE_SpriteLoad ()
#3  0x0000000000402740 in BattlefieldLoad () at battlefield.c:89
#4  0x0000000000402794 in BattlefieldInit (battlefield=0x1dca440, battlefieldId=1)
    at battlefield.c:96
#5  0x0000000000405349 in BattleInitialize (leftTeam=0x60dff0 <leftTeam>, 
    rightTeam=0x60e010 <rightTeam>, battlefieldId=1) at battle.c:13
#6  0x0000000000401e8f in LoadContent () at main.c:90
#7  0x0000000000401d2b in main (argc=1, argv=0x7fffffffdfc8) at main.c:49

It crashed within SDL, and last thing that called it is sprite_free_age. What’s here (AGE/AGE_Sprite.c):

void sprite_free_age(AGE_Sprite *sprite)
{
    if( sprite->texture != NULL )
    {
        SDL_DestroyTexture( sprite->texture );
        sprite->texture = NULL;
        sprite->Width = 0;
        sprite->Height = 0;
    }
}

The only SDL call is SDL_DestroyTexture, and NULL check is performed, which means sprite have garbage data (not NULL but still not an SDL texture but rather something else). It was called from AGE_SpriteLoad:

bool AGE_SpriteLoad(AGE_Sprite *sprite, char *path)
{
    sprite_free_age(sprite);

    SDL_Texture *finalTexture = NULL;
    SDL_Surface *loadedSurface = IMG_Load(path);

    // ... the rest is omitted

So whenever you call AGE_SpriteLoad, it first tries to drop previous sprite it may’ve contained. It was called from BattlefieldLoad at battlefield.c:89:

void BattlefieldLoad()
{
    assert(AGE_SpriteLoad(&squareWalkable, "Resources/Battlefield/SquareWalkable.png"));
    assert(AGE_SpriteLoad(&squareSelected, "Resources/Battlefield/SquareSelected.png"));
    assert(AGE_SpriteLoad(&squareEnemy, "Resources/Battlefield/SquareEnemy.png"));
    assert(AGE_SpriteCreateBlank(&battlefieldField, LevelWidth, LevelHeight, SDL_TEXTUREACCESS_TARGET));
    AGE_ListInit(&objectsList, sizeof(AGE_Sprite));
    AGE_Sprite objectSprite;
    int i;
    char buffer[100];

    for (i = 0; i < BATTLEFIELD_OBJECTS_COUNT; ++i)
    {
        snprintf(buffer, sizeof(buffer), "Resources/Battlefield/Object_%d.png", i+1);
        AGE_SpriteLoad(&objectSprite, buffer);
        AGE_ListAdd(&objectsList, &objectSprite);
    }
}

Here you have uninitialised AGE_Sprite objectSprite, and you’re calling AGE_SpriteLoad on it, which tries to drop old data (which is uninitialised => garbage) and (maybe) crashes. First thing coming to mind is that you need to set objectSprite to zero-bytes, either with memset or just by initialising it upon declaration, e.g. AGE_Sprite objectSprite = {};.

Browse More Popular Posts

Leave a Comment