]> git.alsa-project.org Git - alsa-lib.git/commitdiff
conf: fix snd_func_imul accumulator initialization HEAD master
authorBojan Janjatovic <bojan.janjatovic@mamut-studio.com>
Thu, 7 May 2026 16:46:57 +0000 (18:46 +0200)
committerJaroslav Kysela <perex@perex.cz>
Sun, 5 Jul 2026 16:29:22 +0000 (18:29 +0200)
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
Closes: https://github.com/alsa-project/alsa-lib/pull/511
Signed-off-by: Bojan Janjatovic <bojan.janjatovic@mamut-studio.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/confmisc.c
test/lsb/config.c

index c1f5410c681d619e0086a93eeae6daf32d603f6b..4acc3cd69436b08d1d983eb31a874b646d640990 100644 (file)
@@ -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)
index e8699f138c57b7be0e38129dfc01fbadc4db9057..9906c35598aa520c44513b94f02719a3076deccf 100644 (file)
@@ -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();