From: Aki Tuomi Date: Wed, 19 Mar 2025 08:48:43 +0000 (+0200) Subject: lib-settings: Pad initial var expand context with empty tables and providers when... X-Git-Tag: 2.4.1~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=67ef99c7a14f18938ded67a4cfc7846ebcceae8f;p=thirdparty%2Fdovecot%2Fcore.git lib-settings: Pad initial var expand context with empty tables and providers when needed Fixes: Panic: file settings.c: line 1560 (settings_var_expand_init_add): assertion failed: (I_MAX(num_tables, num_provs) == num_ctx) --- diff --git a/src/lib-settings/settings.c b/src/lib-settings/settings.c index ec60f7ad08..8e4ac6aef9 100644 --- a/src/lib-settings/settings.c +++ b/src/lib-settings/settings.c @@ -1407,33 +1407,67 @@ settings_var_expand_init_add(struct settings_var_expand_init_ctx *init_ctx, const struct var_expand_params *params) { unsigned int need_contexts = 1; + static const struct var_expand_table empty_table[] = { + VAR_EXPAND_TABLE_END + }; + static const struct var_expand_table *empty_table_ptr = empty_table; + static const struct var_expand_provider empty_provider[] = { + VAR_EXPAND_TABLE_END + }; + static const struct var_expand_provider *empty_provider_ptr = empty_provider; + if (params->table != NULL) { i_assert(params->tables_arr == NULL); array_push_back(&init_ctx->tables, ¶ms->table); + } else if (params->tables_arr == NULL && params->providers_arr == NULL) { + array_push_back(&init_ctx->tables, &empty_table_ptr); } if (params->providers != NULL) { i_assert(params->providers_arr == NULL); array_push_back(&init_ctx->providers, ¶ms->providers); + } else if (params->tables_arr == NULL && params->providers_arr == NULL) { + array_push_back(&init_ctx->providers, &empty_provider_ptr); } if (params->table != NULL || params->providers != NULL) array_push_back(&init_ctx->contexts, ¶ms->context); - if (params->tables_arr != NULL) { - for (unsigned int i = 0; params->tables_arr[i] != NULL; i++) { - if (i > need_contexts) - need_contexts = i; - array_push_back(&init_ctx->tables, - ¶ms->tables_arr[i]); - } - } - if (params->providers_arr != NULL) { - for (unsigned int i = 0; params->providers_arr[i] != NULL; i++) { - if (i > need_contexts) - need_contexts = i; - array_push_back(&init_ctx->providers, - ¶ms->providers_arr[i]); - } + if (params->tables_arr != NULL || params->providers_arr != NULL) { + unsigned int table_count = 0, prov_count = 0; + const struct var_expand_table *tbl; + const struct var_expand_provider *prov; + + /* Ensure that we get a table and provider so that contexts line up */ + do { + tbl = params->tables_arr != NULL ? + params->tables_arr[table_count] : NULL; + prov = params->providers_arr != NULL ? + params->providers_arr[prov_count] : NULL; + + /* for each provider and table, there needs to be + a correspoding entry in both arrays to make sure + that when we go through them, we get the correct + context too. + */ + if (tbl != NULL) { + array_push_back(&init_ctx->tables, &tbl); + table_count++; + } else if (prov != NULL) { + array_push_back(&init_ctx->tables, &empty_table_ptr); + } + if (prov != NULL) { + array_push_back(&init_ctx->providers, &prov); + prov_count++; + } else if (tbl != NULL) { + array_push_back(&init_ctx->providers, &empty_provider_ptr); + } + if (prov == NULL && tbl == NULL) + break; + } while (tbl != NULL || prov != NULL); + + if (I_MAX(table_count, prov_count) > need_contexts) + need_contexts = I_MAX(table_count, prov_count); } + if (params->escape_func != NULL) init_ctx->escape_func = params->escape_func; if (params->escape_context != NULL) @@ -1447,6 +1481,11 @@ settings_var_expand_init_add(struct settings_var_expand_init_ctx *init_ctx, array_push_back(&init_ctx->contexts, ctx); } i_assert(count == need_contexts); + } else { + /* Make sure we push some context enough to pad the context stack + to match the number of tables and providers. */ + for (unsigned int i = 1; i < need_contexts; i++) + array_push_back(&init_ctx->contexts, ¶ms->context); } /* ensure everything is still good */