fix memory leaks and other mem-bugs

This commit is contained in:
Sebastian Krzyszkowiak 2016-08-16 18:01:12 +02:00
parent 51b08cee76
commit 686514fba5
5 changed files with 109 additions and 74 deletions

View file

@ -23,7 +23,7 @@
#include "gamestate.h"
#include "internal.h"
SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game) {
SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game, const char* name) {
struct Gamestate *tmp = game->_priv.gamestates;
if (!tmp) {
game->_priv.gamestates = malloc(sizeof(struct Gamestate));
@ -35,7 +35,7 @@ SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game) {
tmp->next = malloc(sizeof(struct Gamestate));
tmp = tmp->next;
}
tmp->name = NULL;
tmp->name = strdup(name);
tmp->handle = NULL;
tmp->loaded = false;
tmp->paused = false;
@ -68,8 +68,7 @@ SYMBOL_EXPORT void LoadGamestate(struct Game *game, const char* name) {
}
gs->pending_load = true;
} else {
gs = AddNewGamestate(game);
gs->name = strdup(name);
gs = AddNewGamestate(game, name);
gs->pending_load = true;
gs->showLoading = true;
}

View file

@ -137,23 +137,55 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game *game) {
}
}
SYMBOL_INTERNAL void* AddGarbage(struct Game *game, void* data) {
if (!game->_priv.garbage) {
game->_priv.garbage = malloc(sizeof(struct libsuperderpy_list));
game->_priv.garbage->data = data;
game->_priv.garbage->next = NULL;
SYMBOL_INTERNAL struct libsuperderpy_list* AddToList(struct libsuperderpy_list *list, void* data) {
if (!list) {
list = malloc(sizeof(struct libsuperderpy_list));
list->data = data;
list->next = NULL;
} else {
struct libsuperderpy_list *garbage = malloc(sizeof(struct libsuperderpy_list));
garbage->next = game->_priv.garbage;
garbage->data = data;
game->_priv.garbage = garbage;
struct libsuperderpy_list *elem = malloc(sizeof(struct libsuperderpy_list));
elem->next = list;
elem->data = data;
list = elem;
}
return list;
}
SYMBOL_INTERNAL struct libsuperderpy_list* RemoveFromList(struct libsuperderpy_list **list, bool (*identity)(struct libsuperderpy_list* elem, void* data), void* data) {
struct libsuperderpy_list *prev = NULL, *tmp = *list, *start = *list;
void* d = NULL;
while (tmp) {
if (identity(tmp, data)) {
if (prev) {
prev->next = tmp->next;
d = tmp->data;
free(tmp);
return d;
} else {
start = tmp->next;
d = tmp->data;
free(tmp);
*list = start;
return d;
}
}
prev = tmp;
tmp = tmp->next;
}
return NULL;
}
SYMBOL_INTERNAL void* AddGarbage(struct Game *game, void* data) {
game->_priv.garbage = AddToList(game->_priv.garbage, data);
return data;
}
SYMBOL_INTERNAL void ClearGarbage(struct Game *game) {
struct libsuperderpy_list *tmp;
while (game->_priv.garbage) {
free(game->_priv.garbage->data);
game->_priv.garbage = game->_priv.garbage->next;
tmp = game->_priv.garbage->next;
free(game->_priv.garbage);
game->_priv.garbage = tmp;
}
}

View file

@ -78,6 +78,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
game->config.height = atoi(GetConfigOptionDefault(game, "SuperDerpy", "height", "720"));
if (game->config.height<180) game->config.height=180;
game->_priv.showconsole = game->config.debug;
if(!al_init_image_addon()) {
fprintf(stderr, "failed to initialize image addon!\n");
/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
@ -167,8 +169,6 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
al_set_mixer_gain(game->audio.music, game->config.music/10.0);
al_set_mixer_gain(game->audio.voice, game->config.voice/10.0);
game->_priv.showconsole = game->config.debug;
setlocale(LC_NUMERIC, "C");
game->_priv.argc = argc;
@ -328,7 +328,6 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game *game) {
tmp=game->_priv.gamestates;
while (tmp) {
if ((tmp->pending_start) && (tmp->loaded)) {
PrintConsole(game, "Starting gamestate \"%s\"...", tmp->name);
al_stop_timer(game->_priv.timer);
@ -415,8 +414,10 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game *game) {
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
game->shuttingdown = true;
ClearGarbage(game);
// in case of restart
struct Gamestate *tmp = game->_priv.gamestates;
struct Gamestate *tmp = game->_priv.gamestates, *pom;
while (tmp) {
if (tmp->started) {
PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
@ -429,14 +430,20 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
dlclose(tmp->handle);
tmp->loaded = false;
}
tmp=tmp->next;
free(tmp->name);
pom = tmp->next;
free(tmp);
tmp=pom;
}
al_clear_to_color(al_map_rgb(0,0,0));
PrintConsole(game, "Shutting down...");
DrawConsole(game);
al_flip_display();
al_rest(0.1);
while (game->_priv.garbage) {
free(game->_priv.garbage->data);
game->_priv.garbage = game->_priv.garbage->next;
}
(*game->_priv.loading.Unload)(game, game->_priv.loading.data);
al_destroy_timer(game->_priv.timer);
Console_Unload(game);
@ -452,8 +459,9 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
al_shutdown_ttf_addon();
al_shutdown_font_addon();
char** argv = game->_priv.argv;
bool restart = game->restart;
free(game);
if (game->restart) {
if (restart) {
execv(argv[0], argv); // FIXME: on OSX there's chdir called which might break it
}
}

View file

@ -50,6 +50,7 @@ SYMBOL_EXPORT void TM_Process(struct Timeline* timeline) {
struct TM_Action *tmp = timeline->queue;
timeline->queue = timeline->queue->next;
(*tmp->function)(timeline->game, tmp, TM_ACTIONSTATE_DESTROY);
TM_DestroyArgs(tmp->arguments);
free(tmp->name);
free(tmp);
}
@ -101,6 +102,7 @@ SYMBOL_EXPORT void TM_Process(struct Timeline* timeline) {
tmp = pom;
pom = pom->next;
} else {
TM_DestroyArgs(pom->arguments);
free(pom->name);
free(pom);
tmp2 = tmp;
@ -264,19 +266,30 @@ SYMBOL_EXPORT struct TM_Action* TM_AddBackgroundAction(struct Timeline* timeline
/*! \brief Predefined action used by TM_AddQueuedBackgroundAction */
SYMBOL_INTERNAL bool runinbackground(struct Game* game, struct TM_Action* action, enum TM_ActionState state) {
if (state != TM_ACTIONSTATE_RUNNING) return false;
int* delay = (int*) action->arguments->next->value;
char* name = (char*) action->arguments->next->next->value;
struct Timeline *timeline = (struct Timeline*) action->arguments->next->next->next->value;
TM_AddBackgroundAction(timeline, action->arguments->value, action->arguments->next->next->next->next, *delay, name);
int* delay = (int*) TM_GetArg(action->arguments, 1);
char* name = (char*) TM_GetArg(action->arguments, 2);
struct Timeline *timeline = (struct Timeline*) TM_GetArg(action->arguments, 3);
struct TM_Arguments *arguments = (struct TM_Arguments*) TM_GetArg(action->arguments, 4);
bool *used = (bool*) TM_GetArg(action->arguments, 5);
if (state == TM_ACTIONSTATE_START) {
TM_AddBackgroundAction(timeline, TM_GetArg(action->arguments, 0), arguments, *delay, name);
*used = true;
}
if (state == TM_ACTIONSTATE_DESTROY) {
free(name);
free(delay);
if (!(*used)) {
TM_DestroyArgs(arguments);
}
free(used);
}
return true;
}
SYMBOL_EXPORT struct TM_Action* TM_AddQueuedBackgroundAction(struct Timeline* timeline, bool (*func)(struct Game*, struct TM_Action*, enum TM_ActionState), struct TM_Arguments* args, int delay, char* name) {
TM_WrapArg(int, del, delay);
struct TM_Arguments* arguments = TM_AddToArgs(NULL, 4, (void*) func, del, strdup(name), (void*) timeline);
arguments->next->next->next->next = args;
TM_WrapArg(bool, used, false);
struct TM_Arguments* arguments = TM_AddToArgs(NULL, 6, (void*) func, del, strdup(name), (void*) timeline, args, used);
return TM_AddAction(timeline, *runinbackground, arguments, "TM_BackgroundAction");
}
@ -294,63 +307,37 @@ SYMBOL_EXPORT void TM_AddDelay(struct Timeline* timeline, int delay) {
SYMBOL_EXPORT void TM_CleanQueue(struct Timeline* timeline) {
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning queue", timeline->name);
struct TM_Action *tmp, *tmp2, *pom = timeline->queue;
tmp = NULL;
struct TM_Action *tmp, *pom = timeline->queue;
while (pom!=NULL) {
if (pom->active) {
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
if (pom->timer) {
al_stop_timer(pom->timer);
al_destroy_timer(pom->timer);
}
} else {
TM_DestroyArgs(pom->arguments);
pom->arguments = NULL;
}
if ((!tmp) || (tmp->next==pom)) {
tmp = pom;
pom = pom->next;
} else {
tmp = pom->next;
free(pom->name);
free(pom);
tmp2 = tmp;
if (!tmp) pom=timeline->queue->next;
else pom=tmp->next;
tmp = tmp2;
pom = tmp;
}
}
// TODO: it shouldn't be needed, but is. Debug!
timeline->queue = NULL;
}
SYMBOL_EXPORT void TM_CleanBackgroundQueue(struct Timeline* timeline) {
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning background queue", timeline->name);
struct TM_Action *tmp, *tmp2, *pom = timeline->background;
tmp = NULL;
struct TM_Action *tmp, *pom = timeline->background;
while (pom!=NULL) {
if (pom->active) {
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
if (pom->timer) {
al_stop_timer(pom->timer);
al_destroy_timer(pom->timer);
}
} else {
TM_DestroyArgs(pom->arguments);
pom->arguments = NULL;
}
if ((!tmp) || (tmp->next==pom)) {
tmp = pom;
pom = pom->next;
} else {
tmp = pom->next;
free(pom->name);
free(pom);
tmp2 = tmp;
if (!tmp) pom=timeline->background->next;
else pom=tmp->next;
tmp = tmp2;
pom = tmp;
}
}
// TODO: it shouldn't be needed, but is. Debug!
timeline->background = NULL;
}
@ -389,6 +376,13 @@ SYMBOL_EXPORT struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int n
return args;
}
SYMBOL_EXPORT void* TM_GetArg(struct TM_Arguments *args, int num) {
for (int i=0; i<num; i++) {
args = args->next;
}
return args->value;
}
SYMBOL_EXPORT void TM_DestroyArgs(struct TM_Arguments* args) {
struct TM_Arguments *pom;
while (args) {

View file

@ -92,6 +92,8 @@ void TM_CleanBackgroundQueue(struct Timeline*);
void TM_Destroy(struct Timeline*);
/*! \brief Add data to TM_Arguments queue. */
struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int num, ...);
/*! \brief Get nth argument from TM_Arguments queue (counted from 0). */
void* TM_GetArg(struct TM_Arguments *args, int num);
/*! \brief Destroy TM_Arguments queue. */
void TM_DestroyArgs(struct TM_Arguments* args);