From 5039d4c5e88268ba386365a9c8f9a2a64a8107d9 Mon Sep 17 00:00:00 2001 From: Bojan Janjatovic Date: Thu, 7 May 2026 18:46:57 +0200 Subject: [PATCH] conf: fix snd_func_imul accumulator initialization snd_func_iops() initialized result to 0 for both iadd and imul. For imul this made every multiplication step multiply by 0, so snd_func_imul() returned 0 for every input since it was added in aa7a0dd7 (2006-10-11). The doxygen example for imul therefore did not match observed behavior. Initialize the accumulator to 1 for imul and keep the empty integers list result as 0. Add table-driven config tests covering iadd and imul single, multi, zero, negative, empty, and out-of-order integer lists. Fixes: https://github.com/alsa-project/alsa-lib/issues/456 Signed-off-by: Bojan Janjatovic --- src/confmisc.c | 8 +++++- test/lsb/config.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/confmisc.c b/src/confmisc.c index c1f5410c6..4acc3cd69 100644 --- a/src/confmisc.c +++ b/src/confmisc.c @@ -488,7 +488,7 @@ static int snd_func_iops(snd_config_t **dst, snd_config_iterator_t i, next; const char *id; char *res = NULL; - long result = 0, val; + long result = op == 1 ? 1 : 0, val; int idx = 0, err, hit; err = snd_config_search(src, "integers", &n); @@ -531,6 +531,9 @@ static int snd_func_iops(snd_config_t **dst, } } } while (hit); + /* Preserve pre-fix behavior for an empty integers list. */ + if (op == 1 && idx == 0) + result = 0; err = snd_config_get_id(src, &id); if (err >= 0) err = snd_config_imake_integer(dst, id, result); @@ -582,6 +585,9 @@ SND_DLSYM_BUILD_VERSION(snd_func_iadd, SND_CONFIG_DLSYM_VERSION_EVALUATE); integers [ 2 3 2 ] } \endcode + * + * \note An empty \c integers list yields 0 (not the multiplicative + * identity 1) for backward compatibility. */ int snd_func_imul(snd_config_t **dst, snd_config_t *root, snd_config_t *src, snd_config_t *private_data) diff --git a/test/lsb/config.c b/test/lsb/config.c index e8699f138..9906c3559 100644 --- a/test/lsb/config.c +++ b/test/lsb/config.c @@ -548,6 +548,74 @@ static void test_for_each(void) ALSA_CHECK(snd_config_delete(c)); } +static void test_evaluate_integer_functions(void) +{ + const char *text = + "sum {\n" + " @func iadd\n" + " integers [ 2 3 5 ]\n" + "}\n" + "product {\n" + " @func imul\n" + " integers [ 2 4 6 ]\n" + "}\n" + "single {\n" + " @func imul\n" + " integers [ 7 ]\n" + "}\n" + "with_zero {\n" + " @func imul\n" + " integers [ 2 0 5 ]\n" + "}\n" + "negative {\n" + " @func imul\n" + " integers [ -2 3 ]\n" + "}\n" + "empty {\n" + " @func imul\n" + " integers [ ]\n" + "}\n" + "out_of_order {\n" + " @func imul\n" + " integers {\n" + " 2 = 5\n" + " 0 = 2\n" + " 1 = 3\n" + " }\n" + "}\n"; + struct { + const char *id; + long result; + } *p, expected[] = { + { .id = "sum", .result = 10 }, + { .id = "product", .result = 48 }, + { .id = "single", .result = 7 }, + { .id = "with_zero", .result = 0 }, + { .id = "negative", .result = -6 }, + { .id = "empty", .result = 0 }, + { .id = "out_of_order", .result = 30 }, + { .id = NULL, .result = 0 }, + }; + snd_config_t *top, *node; + snd_input_t *input; + long value; + + ALSA_CHECK(snd_input_buffer_open(&input, text, strlen(text))); + ALSA_CHECK(snd_config_top(&top)); + ALSA_CHECK(snd_config_load(top, input)); + ALSA_CHECK(snd_input_close(input)); + ALSA_CHECK(snd_config_evaluate(top, top, NULL, NULL)); + + for (p = expected; p->id; p++) { + ALSA_CHECK(snd_config_search(top, p->id, &node)); + TEST_CHECK(snd_config_get_type(node) == SND_CONFIG_TYPE_INTEGER); + ALSA_CHECK(snd_config_get_integer(node, &value)); + TEST_CHECK(value == p->result); + } + + ALSA_CHECK(snd_config_delete(top)); +} + static int _expand_fcn(snd_config_t **dst, const char *s, void *private_data ATTRIBUTE_UNUSED) { if (strcmp(s, "var10") == 0) @@ -644,6 +712,7 @@ int main(void) test_get_ascii(); test_iterators(); test_for_each(); + test_evaluate_integer_functions(); test_evaluate_string(); test_load_string(); return TEST_EXIT_CODE();