From c17d20ab28e0ac7dd527ff840559d96e98931a80 Mon Sep 17 00:00:00 2001 From: neonloop Date: Tue, 10 Aug 2021 21:50:17 +0000 Subject: Fixes core options deallocated by core Some cores free core options after notifying libretro, picoarch cannot rely on them staying around. --- main.c | 2 +- options.c | 176 +++++++++++++++++++++++++++++++++++++++----------------------- options.h | 13 +++-- 3 files changed, 117 insertions(+), 74 deletions(-) diff --git a/main.c b/main.c index d399f7a..9cd0696 100644 --- a/main.c +++ b/main.c @@ -104,7 +104,7 @@ void set_defaults(void) for (size_t i = 0; i < core_options.len; i++) { const char *key = options_get_key(i); if (key) - core_options.entries[i].value = options_default_index(key); + core_options.entries[i].value = core_options.entries[i].default_value; } options_update_changed(); diff --git a/options.c b/options.c index 0262c10..249af71 100644 --- a/options.c +++ b/options.c @@ -75,6 +75,24 @@ static int options_default_override(const char *key) { return -1; } + +static int options_default_index(const char *key, const struct retro_core_option_definition *def) { + const char *value; + int default_override = options_default_override(key); + if (default_override >= 0) + return default_override; + + if (!def) + return 0; + + for(int i = 0; (value = def->values[i].value); i++) { + if (!strcmp(value, def->default_value)) { + return i; + } + } + return 0; +} + void options_init(const struct retro_core_option_definition *defs) { size_t i; @@ -82,7 +100,6 @@ void options_init(const struct retro_core_option_definition *defs) { ; core_options.visible_len = core_options.len = i; - core_options.defs = defs; core_options.entries = (struct core_option_entry *)calloc(core_options.len, sizeof(struct core_option_entry)); if (!core_options.entries) { @@ -93,7 +110,7 @@ void options_init(const struct retro_core_option_definition *defs) { for (i = 0; i < core_options.len; i++) { int j, len; - const struct retro_core_option_definition *def = &core_options.defs[i]; + const struct retro_core_option_definition *def = &defs[i]; struct core_option_entry *entry = &core_options.entries[i]; len = strlen(def->key) + 1; @@ -105,9 +122,9 @@ void options_init(const struct retro_core_option_definition *defs) { } strncpy(entry->key, def->key, len); - entry->def = def; - entry->value = options_default_index(def->key); + entry->value = options_default_index(def->key, def); entry->prev_value = entry->value; + entry->default_value = entry->value; entry->blocked = option_blocked(def->key); if (entry->blocked) core_options.visible_len--; @@ -139,20 +156,49 @@ void options_init(const struct retro_core_option_definition *defs) { ; j++; /* Make room for NULL entry */ - entry->options = (const char **)calloc(j, sizeof(char *)); - if (!entry->options) { + entry->values = (char **)calloc(j, sizeof(char *)); + if (!entry->values) { PA_ERROR("Error allocating option entries\n"); options_free(); return; } + entry->labels = (char **)calloc(j, sizeof(char *)); + if (!entry->labels) { + PA_ERROR("Error allocating option entries\n"); + options_free(); + return; + } for (j = 0; def->values[j].value; j++) { + const char *value = def->values[j].value; + size_t value_len = strlen(value); const char *label = def->values[j].label; - if (!label) { - label = def->values[j].value; + size_t label_len = 0; + + entry->values[j] = (char *)calloc(value_len + 1, sizeof(char)); + if (!entry->values[j]) { + PA_ERROR("Error allocating memory for option values"); + options_free(); + return; + } + + strncpy(entry->values[j], value, value_len); + + if (label) { + label_len = strlen(label); + + entry->labels[j] = (char *)calloc(label_len + 1, sizeof(char)); + if (!entry->labels[j]) { + PA_ERROR("Error allocating memory for option labels"); + options_free(); + return; + } + + strncpy(entry->labels[j], label, label_len); + } else { + entry->labels[j] = entry->values[j]; } - entry->options[j] = label; } } } @@ -190,8 +236,9 @@ void options_init_variables(const struct retro_variable *vars) { } strncpy(entry->key, var->key, len); - entry->value = options_default_index(var->key); + entry->value = options_default_index(var->key, NULL); entry->prev_value = entry->value; + entry->default_value = entry->value; entry->blocked = option_blocked(var->key); if (entry->blocked) core_options.visible_len--; @@ -224,8 +271,15 @@ void options_init_variables(const struct retro_variable *vars) { j++; /* Make room for last entry (not ending in |) */ j++; /* Make room for NULL entry */ - entry->options = (const char **)calloc(j, sizeof(char *)); - if (!entry->options) { + entry->values = (char **)calloc(j, sizeof(char *)); + if (!entry->values) { + PA_ERROR("Error allocating option entries\n"); + options_free(); + return; + } + + entry->labels = (char **)calloc(j, sizeof(char *)); + if (!entry->labels) { PA_ERROR("Error allocating option entries\n"); options_free(); return; @@ -233,12 +287,14 @@ void options_init_variables(const struct retro_variable *vars) { p = opt_ptr; for (j = 0; (p = strchr(p, '|')); j++) { - entry->options[j] = opt_ptr; + entry->values[j] = opt_ptr; + entry->labels[j] = opt_ptr; *p = '\0'; p++; opt_ptr = p; } - entry->options[j] = opt_ptr; + entry->values[j] = opt_ptr; + entry->labels[j] = opt_ptr; } } @@ -287,13 +343,9 @@ bool options_is_blocked(const char *key) { const char* options_get_value(const char* key) { struct core_option_entry* entry = options_get_entry(key); - if (entry) { - if (entry->def) { - return entry->def->values[entry->value].value; - } else { - return entry->options[entry->value]; - } - } + if (entry) + return entry->values[entry->value]; + return NULL; } @@ -316,24 +368,14 @@ int options_get_value_index(const char* key) { void options_set_value(const char* key, const char *value) { struct core_option_entry* entry = options_get_entry(key); if (entry) { - const char *option = NULL; - entry->value = options_default_index(key); - - if (entry->def) { - for (int i = 0; (option = entry->def->values[i].value); i++) { - if (!strcmp(option, value)) { - entry->value = i; - options_update_changed(); - return; - } - } - } else { - for (int i = 0; (option = entry->options[i]); i++) { - if (!strcmp(option, value)) { - entry->value = i; - options_update_changed(); - return; - } + char *option; + entry->value = entry->default_value; + + for (int i = 0; (option = entry->values[i]); i++) { + if (!strcmp(option, value)) { + entry->value = i; + options_update_changed(); + return; } } } @@ -347,29 +389,10 @@ void options_set_value_index(const char* key, int value) { } } -int options_default_index(const char *key) { - const char *value; - struct core_option_entry *entry; - int default_override = options_default_override(key); - if (default_override >= 0) - return default_override; - - entry = options_get_entry(key); - if (!entry || !entry->def) - return 0; - - for(int i = 0; (value = entry->def->values[i].value); i++) { - if (!strcmp(value, entry->def->default_value)) { - return i; - } - } - return 0; -} - const char** options_get_options(const char* key) { struct core_option_entry* entry = options_get_entry(key); if (entry) { - return entry->options; + return (const char **)entry->labels; } return NULL; } @@ -378,17 +401,38 @@ void options_free(void) { if (core_options.entries) { for (size_t i = 0; i < core_options.len; i++) { struct core_option_entry* entry = &core_options.entries[i]; - if (entry->options) { - free(entry->options); - } if (entry->retro_var_value) { + /* option values / labels are all pointers into retro_var_value, + * no need to free them one by one */ free(entry->retro_var_value); - } else if (entry->desc) { - free(entry->desc); + } else { + if (entry->labels) { + char *label; + for (int j = 0; (label = entry->labels[j]); j++) { + if (label != entry->values[j]) + free(label); + } + } + + if (entry->values) { + char *value; + for (int j = 0; (value = entry->values[j]); j++) { + free(value); + } + } + + if (entry->desc) + free(entry->desc); } - if (entry->key) { + + if (entry->labels) + free(entry->labels); + + if (entry->values) + free(entry->values); + + if (entry->key) free(entry->key); - } } free(core_options.entries); } diff --git a/options.h b/options.h index f1ae5e7..fde4616 100644 --- a/options.h +++ b/options.h @@ -12,14 +12,15 @@ extern enum scale_filter scale_filter; struct core_option_entry { char *key; + char *desc; + char *info; int value; int prev_value; - char *desc; - char *retro_var_value; + int default_value; bool blocked; - char *info; - const char **options; - const struct retro_core_option_definition *def; + char **values; + char **labels; + char *retro_var_value; }; struct core_options { @@ -27,7 +28,6 @@ struct core_options { size_t visible_len; bool changed; struct core_option_entry *entries; - const struct retro_core_option_definition *defs; }; extern struct core_options core_options; @@ -48,7 +48,6 @@ int options_get_value_index(const char* key); void options_set_value(const char* key, const char *value); void options_set_value_index(const char* key, int value); -int options_default_index(const char *key); const char** options_get_options(const char* key); void options_free(void); -- cgit v1.2.3