C/SDL - 程序连续多次 运行 时出现段错误
C/SDL - Segmentation fault when program run multiple times in succession
我在我的程序中遇到了一些奇怪的行为。
当我 运行 我的程序 3-4 次并立即关闭它时,它甚至在开始之前就开始给我分段错误。当我有一段时间没有打开它时,它会毫无问题地打开前 2-3 次,然后再次出现段错误。
对于导致此类问题的原因,我乐于接受建议。
该项目很大,所以我不知道该去哪里看,所以如果有人想查看源代码,请看这里:
https://github.com/rokn/Helsys3
让我为您分解一个调试会话,但以后您最好自己动手。
如果问题很容易重现,修复它就很简单了:
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
它在 SDL 中崩溃,最后调用它的是 sprite_free_age
。这里有什么 (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;
}
}
唯一的 SDL 调用是 SDL_DestroyTexture
,并且执行了 NULL 检查,这意味着 sprite
有垃圾数据(不是 NULL 但仍然不是 SDL 纹理而是其他东西)。它是从 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
因此,无论何时您调用 AGE_SpriteLoad
,它都会首先尝试删除它可能包含的先前精灵。它是从 BattlefieldLoad
在 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);
}
}
这里你有未初始化的 AGE_Sprite objectSprite
,你在上面调用 AGE_SpriteLoad
,它试图删除旧数据(未初始化的 => 垃圾)和(可能)崩溃。首先想到的是您需要将 objectSprite
设置为零字节,可以使用 memset
或仅在声明时初始化它,例如AGE_Sprite objectSprite = {};
.
我在我的程序中遇到了一些奇怪的行为。
当我 运行 我的程序 3-4 次并立即关闭它时,它甚至在开始之前就开始给我分段错误。当我有一段时间没有打开它时,它会毫无问题地打开前 2-3 次,然后再次出现段错误。
对于导致此类问题的原因,我乐于接受建议。 该项目很大,所以我不知道该去哪里看,所以如果有人想查看源代码,请看这里: https://github.com/rokn/Helsys3
让我为您分解一个调试会话,但以后您最好自己动手。
如果问题很容易重现,修复它就很简单了:
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
它在 SDL 中崩溃,最后调用它的是 sprite_free_age
。这里有什么 (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;
}
}
唯一的 SDL 调用是 SDL_DestroyTexture
,并且执行了 NULL 检查,这意味着 sprite
有垃圾数据(不是 NULL 但仍然不是 SDL 纹理而是其他东西)。它是从 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
因此,无论何时您调用 AGE_SpriteLoad
,它都会首先尝试删除它可能包含的先前精灵。它是从 BattlefieldLoad
在 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);
}
}
这里你有未初始化的 AGE_Sprite objectSprite
,你在上面调用 AGE_SpriteLoad
,它试图删除旧数据(未初始化的 => 垃圾)和(可能)崩溃。首先想到的是您需要将 objectSprite
设置为零字节,可以使用 memset
或仅在声明时初始化它,例如AGE_Sprite objectSprite = {};
.