The patch "Replace atoi() with a robust strtoi()" introduced a bug
in parse_cpu_set(), which relies on partial parsing of the input
string.

Restore the original use of atoi() in parse_cpu_set().

Add a unit test to prevent accidental regressions.

Fixes: 7e9dfccf8f11 ("rtla: Replace atoi() with a robust strtoi()")

Signed-off-by: Costa Shulyupin <[email protected]>
---
 tools/tracing/rtla/Makefile           |  3 ++
 tools/tracing/rtla/src/utils.c        | 10 ++--
 tools/tracing/rtla/tests/Makefile     | 12 +++++
 tools/tracing/rtla/tests/test_utils.c | 74 +++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 6 deletions(-)
 create mode 100644 tools/tracing/rtla/tests/Makefile
 create mode 100644 tools/tracing/rtla/tests/test_utils.c

diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile
index 2701256abaf3..1805916c7dba 100644
--- a/tools/tracing/rtla/Makefile
+++ b/tools/tracing/rtla/Makefile
@@ -109,7 +109,10 @@ clean: doc_clean fixdep-clean
        $(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-*
        $(Q)rm -rf feature
        $(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h 
example/timerlat_bpf_action.o
+
 check: $(RTLA) tests/bpf/bpf_action_map.o
+       make -C tests/ check
        RTLA=$(RTLA) BPFTOOL=$(SYSTEM_BPFTOOL) prove -o -f -v tests/
+
 examples: example/timerlat_bpf_action.o
 .PHONY: FORCE clean check
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 18986a5aed3c..0da3b2470c31 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -128,18 +128,16 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set)
        nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
 
        for (p = cpu_list; *p; ) {
-               if (strtoi(p, &cpu))
-                       goto err;
-               if (cpu < 0 || cpu >= nr_cpus)
+               cpu = atoi(p);
+               if (cpu < 0 || (!cpu && *p != '0') || cpu >= nr_cpus)
                        goto err;
 
                while (isdigit(*p))
                        p++;
                if (*p == '-') {
                        p++;
-                       if (strtoi(p, &end_cpu))
-                               goto err;
-                       if (end_cpu < cpu || end_cpu >= nr_cpus)
+                       end_cpu = atoi(p);
+                       if (end_cpu < cpu || (!end_cpu && *p != '0') || end_cpu 
>= nr_cpus)
                                goto err;
                        while (isdigit(*p))
                                p++;
diff --git a/tools/tracing/rtla/tests/Makefile 
b/tools/tracing/rtla/tests/Makefile
new file mode 100644
index 000000000000..fe187306a404
--- /dev/null
+++ b/tools/tracing/rtla/tests/Makefile
@@ -0,0 +1,12 @@
+LIBS := -lcheck
+
+test_utils: test_utils.c ../src/utils.c
+       $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+
+check: test_utils
+       ./test_utils
+
+clean:
+       rm -f test_utils
+
+.PHONY: check clean
diff --git a/tools/tracing/rtla/tests/test_utils.c 
b/tools/tracing/rtla/tests/test_utils.c
new file mode 100644
index 000000000000..92ed49d60d33
--- /dev/null
+++ b/tools/tracing/rtla/tests/test_utils.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Unit tests for src/utils.c parsing functions
+ */
+
+#define _GNU_SOURCE
+#include <check.h>
+#include <unistd.h>
+
+#include "../src/utils.h"
+
+START_TEST(test_parse_cpu_set)
+{
+       cpu_set_t set;
+       int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+
+       ck_assert_int_eq(parse_cpu_set("0", &set), 0);
+       ck_assert(CPU_ISSET(0, &set));
+       ck_assert(!CPU_ISSET(1, &set));
+
+       if (nr_cpus > 2) {
+               ck_assert_int_eq(parse_cpu_set("0,2", &set), 0);
+               ck_assert(CPU_ISSET(0, &set));
+               ck_assert(CPU_ISSET(2, &set));
+       }
+
+       if (nr_cpus > 3) {
+               ck_assert_int_eq(parse_cpu_set("0-3", &set), 0);
+               ck_assert(CPU_ISSET(0, &set));
+               ck_assert(CPU_ISSET(1, &set));
+               ck_assert(CPU_ISSET(2, &set));
+               ck_assert(CPU_ISSET(3, &set));
+       }
+
+       if (nr_cpus > 5) {
+               ck_assert_int_eq(parse_cpu_set("1-3,5", &set), 0);
+               ck_assert(!CPU_ISSET(0, &set));
+               ck_assert(CPU_ISSET(1, &set));
+               ck_assert(CPU_ISSET(2, &set));
+               ck_assert(CPU_ISSET(3, &set));
+               ck_assert(!CPU_ISSET(4, &set));
+               ck_assert(CPU_ISSET(5, &set));
+       }
+
+       ck_assert_int_ne(parse_cpu_set("-1", &set), 0);
+       ck_assert_int_ne(parse_cpu_set("abc", &set), 0);
+       ck_assert_int_ne(parse_cpu_set("9999", &set), 0);
+}
+END_TEST
+
+Suite *utils_suite(void)
+{
+       Suite *s = suite_create("utils");
+       TCase *tc = tcase_create("core");
+
+       tcase_add_test(tc, test_parse_cpu_set);
+
+       suite_add_tcase(s, tc);
+       return s;
+}
+
+int main(void)
+{
+       int num_failed;
+       SRunner *sr;
+
+       sr = srunner_create(utils_suite());
+       srunner_run_all(sr, CK_NORMAL);
+       num_failed = srunner_ntests_failed(sr);
+
+       srunner_free(sr);
+
+       return (num_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-- 
2.52.0


Reply via email to