summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2021-07-22 11:37:27 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2021-07-22 12:53:08 +1000
commit492f6817d37d05064d50e93d3abe4600768ab3d3 (patch)
tree585bc45b36a251f2229638ade2ed71f60af6eb22
parent29d311d634b8e0b249699c89107589a968ae53ac (diff)
util-list: restore list_for_each_safe() to be a single statement
3d3d9b7f69b1119523becab3160378066db2e1c0 got rid of the need for a tmp argument for list_for_each_safe() but switched the loop to be a multiline statement. This could potentially cause bugs where the loop is used inside a block without curly braces, e.g. if (condition) list_for_each_safe() func() The assignment preceding the actual loop would result in the code reading as: if (condition) pos = .... list_for_each_safe() The actual list loop would be unconditional. Fix this by moving the initial assignment into an expression statement. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/util-list.h6
-rw-r--r--test/test-utils.c34
2 files changed, 38 insertions, 2 deletions
diff --git a/src/util-list.h b/src/util-list.h
index 5220c7ba..6c7f3bdf 100644
--- a/src/util-list.h
+++ b/src/util-list.h
@@ -189,8 +189,10 @@ bool list_empty(const struct list *list);
* @endcode
*/
#define list_for_each_safe(pos, head, member) \
- pos = list_first_entry_by_type(head, __typeof__(*pos), member); \
- for (__typeof__(pos) _tmp = list_first_entry_by_type(&pos->member, __typeof__(*_tmp), member); \
+ for (__typeof__(pos) _tmp = ({ \
+ pos = list_first_entry_by_type(head, __typeof__(*pos), member); \
+ list_first_entry_by_type(&pos->member, __typeof__(*_tmp), member); \
+ }); \
&pos->member != (head); \
pos = _tmp, \
_tmp = list_first_entry_by_type(&pos->member, __typeof__(*_tmp), member))
diff --git a/test/test-utils.c b/test/test-utils.c
index 882ee6c7..bdefd794 100644
--- a/test/test-utils.c
+++ b/test/test-utils.c
@@ -1295,6 +1295,39 @@ START_TEST(list_test_append)
}
END_TEST
+START_TEST(list_test_foreach)
+{
+ struct list_test {
+ int val;
+ struct list node;
+ } tests[] = {
+ { .val = 1 },
+ { .val = 2 },
+ { .val = 3 },
+ { .val = 4 },
+ };
+ struct list_test *t;
+ struct list head;
+
+ list_init(&head);
+
+ ARRAY_FOR_EACH(tests, t) {
+ list_append(&head, &t->node);
+ }
+
+ /* Make sure both loop macros are a single line statement */
+ if (false)
+ list_for_each(t, &head, node) {
+ ck_abort_msg("We should not get here");
+ }
+
+ if (false)
+ list_for_each_safe(t, &head, node) {
+ ck_abort_msg("We should not get here");
+ }
+}
+END_TEST
+
START_TEST(strverscmp_test)
{
ck_assert_int_eq(libinput_strverscmp("", ""), 0);
@@ -1427,6 +1460,7 @@ litest_utils_suite(void)
tcase_add_test(tc, list_test_insert);
tcase_add_test(tc, list_test_append);
+ tcase_add_test(tc, list_test_foreach);
tcase_add_test(tc, strverscmp_test);
tcase_add_test(tc, streq_test);
tcase_add_test(tc, strneq_test);