From: Jaroslav Kysela Date: Fri, 7 Nov 2025 16:59:12 +0000 (+0100) Subject: ucm: fix variant issue where variables or macros are overwritten X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=bd0ce670c2f2d3eb14f9f5cc153f7112199b96da;p=alsa-lib.git ucm: fix variant issue where variables or macros are overwritten It is necessary to reset the state logic before each verb variant is parsed. So save the original variable list and macros and restore them before each parser iteration. BugLink: https://github.com/alsa-project/alsa-ucm-conf/pull/633 Signed-off-by: Jaroslav Kysela --- diff --git a/src/ucm/parser.c b/src/ucm/parser.c index d46ec87a..7a8c6d39 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -2250,15 +2250,52 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, err = parse_verb_file(uc_mgr, use_case_name, comment, file); } else { /* parse variants */ + struct list_head orig_variable_list; + snd_config_t *orig_macros = NULL; + int first_iteration = 1; + + /* save original variable list */ + err = uc_mgr_duplicate_variables(&orig_variable_list, &uc_mgr->variable_list); + if (err < 0) + goto __error; + + /* save original macros */ + if (uc_mgr->macros) { + err = snd_config_copy(&orig_macros, uc_mgr->macros); + if (err < 0) + goto __variant_error; + } + snd_config_for_each(i, next, variant) { char *vfile, *vcomment; const char *id; + + /* restore variables and macros for second and later iterations */ + if (!first_iteration) { + uc_mgr_free_value(&uc_mgr->variable_list); + + err = uc_mgr_duplicate_variables(&uc_mgr->variable_list, &orig_variable_list); + if (err < 0) + goto __variant_error; + + if (uc_mgr->macros) { + snd_config_delete(uc_mgr->macros); + uc_mgr->macros = NULL; + } + if (orig_macros) { + err = snd_config_copy(&uc_mgr->macros, orig_macros); + if (err < 0) + goto __variant_error; + } + } + first_iteration = 0; + n = snd_config_iterator_entry(i); if (snd_config_get_id(n, &id) < 0) continue; if (!parse_is_name_safe(id)) { err = -EINVAL; - goto __error; + goto __variant_error; } err = parse_variant(uc_mgr, n, &vfile, &vcomment); if (err < 0) @@ -2270,7 +2307,14 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, uc_mgr->parse_variant = NULL; free(vfile); free(vcomment); + if (err < 0) + break; } + +__variant_error: + uc_mgr_free_value(&orig_variable_list); + if (orig_macros) + snd_config_delete(orig_macros); } __error: diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index 18b29871..5e9b23fb 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -327,6 +327,8 @@ struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr, snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr); +void uc_mgr_free_value(struct list_head *base); + int uc_mgr_add_value(struct list_head *base, const char *key, char *val); const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr, @@ -338,6 +340,8 @@ int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr, int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name); +int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src); + int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, char **_rvalue, const char *value); diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 67d51226..8b591cee 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -733,6 +733,39 @@ int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name) return -ENOENT; } +int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src) +{ + struct list_head *pos; + struct ucm_value *var, *new_var; + int err; + + INIT_LIST_HEAD(dst); + + list_for_each(pos, src) { + var = list_entry(pos, struct ucm_value, list); + new_var = calloc(1, sizeof(*new_var)); + if (new_var == NULL) { + err = -ENOMEM; + goto __error; + } + new_var->name = strdup(var->name); + new_var->data = strdup(var->data); + if (new_var->name == NULL || new_var->data == NULL) { + free(new_var->name); + free(new_var->data); + free(new_var); + err = -ENOMEM; + goto __error; + } + list_add_tail(&new_var->list, dst); + } + return 0; + +__error: + uc_mgr_free_value(dst); + return err; +} + void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) { struct list_head *pos, *npos;