fix llist_for_each_entry*
authorjsg <jsg@openbsd.org>
Wed, 27 Jul 2022 06:57:06 +0000 (06:57 +0000)
committerjsg <jsg@openbsd.org>
Wed, 27 Jul 2022 06:57:06 +0000 (06:57 +0000)
enabling more of __notify_execute_cb() and running the intel xorg driver
on broadwell would fault in __notify_execute_cb() on
movq 0x38(%rsi),%r12

offsetof(struct execute_cb, work.node.llist) 0x38

llist_entry(NULL must not return NULL, it needs to wrap around
and return NULL minus the offset

the iterators stop when the offset added back to the result of
llist_entry() is NULL

they test that the first node is not NULL or that the next pointer
stored in a previous iteration of the loop is not NULL

sys/dev/pci/drm/include/linux/llist.h

index 8c0b37d..2e518eb 100644 (file)
@@ -13,8 +13,7 @@ struct llist_head {
        struct llist_node *first;
 };
 
-#define llist_entry(ptr, type, member) \
-       ((ptr) ? container_of(ptr, type, member) : NULL)
+#define llist_entry(ptr, type, member) container_of(ptr, type, member)
 
 static inline struct llist_node *
 llist_del_all(struct llist_head *head)
@@ -82,13 +81,13 @@ llist_empty(struct llist_head *head)
 
 #define llist_for_each_entry_safe(pos, n, node, member)                \
        for (pos = llist_entry((node), __typeof(*pos), member);         \
-           pos != NULL &&                                              \
+           ((char *)(pos) + offsetof(typeof(*(pos)), member)) != NULL && \
            (n = llist_entry(pos->member.next, __typeof(*pos), member), pos); \
            pos = n)
 
 #define llist_for_each_entry(pos, node, member)                                \
        for ((pos) = llist_entry((node), __typeof(*(pos)), member);     \
-           (pos) != NULL;                                              \
+           ((char *)(pos) + offsetof(typeof(*(pos)), member)) != NULL; \
            (pos) = llist_entry((pos)->member.next, __typeof(*(pos)), member))
 
 #endif