fix a whole bunch of memory leaks

This commit is contained in:
Brad Parker 2019-03-01 12:05:14 -05:00
parent a09e110d24
commit e0b75ec3fb
4 changed files with 88 additions and 26 deletions

View File

@ -209,8 +209,10 @@ void task_queue_retrieve(task_retriever_data_t *data);
void task_queue_check(void); void task_queue_check(void);
/* Pushes a task /* Pushes a task
* The task will start as soon as possible. */ * The task will start as soon as possible.
void task_queue_push(retro_task_t *task); * If a second blocking task is attempted, false will be returned
* and the task will be ignored. */
bool task_queue_push(retro_task_t *task);
/* Blocks until all tasks have finished /* Blocks until all tasks have finished
* will return early if cond is not NULL * will return early if cond is not NULL

View File

@ -610,7 +610,7 @@ void task_queue_check(void)
impl_current->gather(); impl_current->gather();
} }
void task_queue_push(retro_task_t *task) bool task_queue_push(retro_task_t *task)
{ {
/* Ignore this task if a related one is already running */ /* Ignore this task if a related one is already running */
if (task->type == TASK_TYPE_BLOCKING) if (task->type == TASK_TYPE_BLOCKING)
@ -634,12 +634,14 @@ void task_queue_push(retro_task_t *task)
/* skip this task, user must try again later */ /* skip this task, user must try again later */
if (found) if (found)
return; return false;
} }
/* The lack of NULL checks in the following functions /* The lack of NULL checks in the following functions
* is proposital to ensure correct control flow by the users. */ * is proposital to ensure correct control flow by the users. */
impl_current->push_running(task); impl_current->push_running(task);
return true;
} }
void task_queue_wait(retro_task_condition_fn_t cond, void* data) void task_queue_wait(retro_task_condition_fn_t cond, void* data)

View File

@ -511,6 +511,8 @@ static void undo_save_state_cb(retro_task_t *task,
void *task_data, void *task_data,
void *user_data, const char *error) void *user_data, const char *error)
{ {
save_task_state_t *state = (save_task_state_t*)task_data;
/* Wipe the save file buffer as it's intended to be one use only */ /* Wipe the save file buffer as it's intended to be one use only */
undo_save_buf.path[0] = '\0'; undo_save_buf.path[0] = '\0';
undo_save_buf.size = 0; undo_save_buf.size = 0;
@ -519,6 +521,8 @@ static void undo_save_state_cb(retro_task_t *task,
free(undo_save_buf.data); free(undo_save_buf.data);
undo_save_buf.data = NULL; undo_save_buf.data = NULL;
} }
free(state);
} }
/** /**
@ -563,6 +567,9 @@ void* get_serialized_data(const char *path, size_t serial_size)
bool ret = false; bool ret = false;
void *data = NULL; void *data = NULL;
if (!serial_size)
return NULL;
data = malloc(serial_size); data = malloc(serial_size);
if (!data) if (!data)
@ -576,12 +583,14 @@ void* get_serialized_data(const char *path, size_t serial_size)
serial_info.data = data; serial_info.data = data;
serial_info.size = serial_size; serial_info.size = serial_size;
ret = core_serialize(&serial_info); ret = core_serialize(&serial_info);
if ( !ret )
if (!ret)
{ {
free(data) ; free(data);
return NULL ; return NULL;
} }
return data ;
return data;
} }
/** /**
@ -607,7 +616,7 @@ static void task_save_handler(retro_task_t *task)
} }
if (!state->data) if (!state->data)
state->data = get_serialized_data(state->path, state->size) ; state->data = get_serialized_data(state->path, state->size);
remaining = MIN(state->size - state->written, SAVE_STATE_CHUNK); remaining = MIN(state->size - state->written, SAVE_STATE_CHUNK);
@ -1054,6 +1063,7 @@ static void save_state_cb(retro_task_t *task,
take_screenshot(path, true, state->has_valid_framebuffer, false, true); take_screenshot(path, true, state->has_valid_framebuffer, false, true);
free(path); free(path);
free(state);
} }
/** /**
@ -1089,7 +1099,16 @@ static void task_push_save_state(const char *path, void *data, size_t size, bool
task->title = strdup(msg_hash_to_str(MSG_SAVING_STATE)); task->title = strdup(msg_hash_to_str(MSG_SAVING_STATE));
task->mute = state->mute; task->mute = state->mute;
task_queue_push(task); if (!task_queue_push(task))
{
/* Another blocking task is already active. */
if (data)
free(data);
if (task->title)
task_free_title(task);
free(task);
free(state);
}
return; return;
@ -1099,7 +1118,11 @@ error:
if (state) if (state)
free(state); free(state);
if (task) if (task)
{
if (task->title)
task_free_title(task);
free(task); free(task);
}
} }
/** /**
@ -1163,7 +1186,16 @@ static void task_push_load_and_save_state(const char *path, void *data,
task->title = strdup(msg_hash_to_str(MSG_LOADING_STATE)); task->title = strdup(msg_hash_to_str(MSG_LOADING_STATE));
task->mute = state->mute; task->mute = state->mute;
task_queue_push(task); if (!task_queue_push(task))
{
/* Another blocking task is already active. */
if (data)
free(data);
if (task->title)
task_free_title(task);
free(task);
free(state);
}
return; return;
@ -1194,13 +1226,13 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave)
if (info.size == 0) if (info.size == 0)
return false; return false;
if ( !save_state_in_background ) if (!save_state_in_background)
{ {
RARCH_LOG("%s: \"%s\".\n", RARCH_LOG("%s: \"%s\".\n",
msg_hash_to_str(MSG_SAVING_STATE), msg_hash_to_str(MSG_SAVING_STATE),
path); path);
data = get_serialized_data(path, info.size) ; data = get_serialized_data(path, info.size);
if (!data) if (!data)
{ {
@ -1214,7 +1246,6 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave)
msg_hash_to_str(MSG_STATE_SIZE), msg_hash_to_str(MSG_STATE_SIZE),
(int)info.size, (int)info.size,
msg_hash_to_str(MSG_BYTES)); msg_hash_to_str(MSG_BYTES));
} }
if (save_to_disk) if (save_to_disk)
@ -1234,15 +1265,15 @@ bool content_save_state(const char *path, bool save_to_disk, bool autosave)
} }
else else
{ {
if ( data == NULL ) if (data == NULL)
data = get_serialized_data(path, info.size) ; data = get_serialized_data(path, info.size);
if ( data == NULL ) if (data == NULL)
{ {
RARCH_ERR("%s \"%s\".\n", RARCH_ERR("%s \"%s\".\n",
msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO),
path); path);
return false ; return false;
} }
/* save_to_disk is false, which means we are saving the state /* save_to_disk is false, which means we are saving the state
in undo_load_buf to allow content_undo_load_state() to restore it */ in undo_load_buf to allow content_undo_load_state() to restore it */
@ -1528,7 +1559,7 @@ bool event_save_files(void)
{ {
unsigned i; unsigned i;
cheat_manager_save_game_specific_cheats() ; cheat_manager_save_game_specific_cheats();
if (!task_save_files || if (!task_save_files ||
!rarch_ctl(RARCH_CTL_IS_SRAM_USED, NULL)) !rarch_ctl(RARCH_CTL_IS_SRAM_USED, NULL))
return false; return false;
@ -1594,5 +1625,5 @@ void *savefile_ptr_get(void)
void set_save_state_in_background(bool state) void set_save_state_in_background(bool state)
{ {
save_state_in_background = state ; save_state_in_background = state;
} }

View File

@ -49,6 +49,7 @@
#include "../retroarch.h" #include "../retroarch.h"
#include "../paths.h" #include "../paths.h"
#include "../msg_hash.h" #include "../msg_hash.h"
#include "../verbosity.h"
#include "../gfx/video_driver.h" #include "../gfx/video_driver.h"
@ -143,6 +144,9 @@ static void task_screenshot_handler(retro_task_t *task)
{ {
task_set_finished(task, true); task_set_finished(task, true);
if (task->title)
task_free_title(task);
if (state->userbuf) if (state->userbuf)
free(state->userbuf); free(state->userbuf);
@ -173,6 +177,9 @@ static void task_screenshot_handler(retro_task_t *task)
runloop_msg_queue_push(msg, 1, state->is_paused ? 1 : 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); runloop_msg_queue_push(msg, 1, state->is_paused ? 1 : 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
free(msg); free(msg);
} }
if (task->title)
task_free_title(task);
} }
/* Take frame bottom-up. */ /* Take frame bottom-up. */
@ -191,17 +198,19 @@ static bool screenshot_dump(
char screenshot_path[PATH_MAX_LENGTH]; char screenshot_path[PATH_MAX_LENGTH];
uint8_t *buf = NULL; uint8_t *buf = NULL;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
retro_task_t *task = task_init(); retro_task_t *task;
screenshot_task_state_t *state = (screenshot_task_state_t*) screenshot_task_state_t *state;
calloc(1, sizeof(*state));
const char *screenshot_dir = settings->paths.directory_screenshot; const char *screenshot_dir = settings->paths.directory_screenshot;
struct retro_system_info system_info; struct retro_system_info system_info;
state->shotname[0] = '\0';
screenshot_path[0] = '\0'; screenshot_path[0] = '\0';
if (!core_get_system_info(&system_info)) if (!core_get_system_info(&system_info))
return false; return false;
task = task_init();
state = (screenshot_task_state_t*)calloc(1, sizeof(*state));
state->shotname[0] = '\0';
/* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */ /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */
if (fullpath) if (fullpath)
@ -282,10 +291,28 @@ static bool screenshot_dump(
if (!savestate) if (!savestate)
task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT));
task_queue_push(task); if (!task_queue_push(task))
{
/* There is already a blocking task going on */
if (task->title)
task_free_title(task);
free(task);
if (state->out_buffer)
free(state->out_buffer);
free(state);
return false;
}
} }
else else
{
if (task)
free(task);
return screenshot_dump_direct(state); return screenshot_dump_direct(state);
}
return true; return true;
} }