linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 1/4] rcu: rcupdate.h: Add missing parentheses around macro pointer dereference
@ 2023-05-04  1:29 Mathieu Desnoyers
  2023-05-04  1:29 ` [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use Mathieu Desnoyers
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04  1:29 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, Mathieu Desnoyers, Boqun Feng, Steven Rostedt,
	Joel Fernandes, Paul E. McKenney, Josh Triplett, Lai Jiangshan,
	Zqiang

linux/rcupdate.h macros use the *p parameter without parentheses, e.g.:

  typeof(*p)

rather than

  typeof(*(p))

The following test-case shows how it can generate confusion due to C
operator precedence being reversed compared to the expectations:

    #define m(p) \
    do { \
            __typeof__(*p) v = 0; \
    } while (0)

    void fct(unsigned long long *p1)
    {
            m(p1 + 1);      /* works */
            m(1 + p1);      /* broken */
    }

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Joel Fernandes <joel@joelfernandes.org>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Lai Jiangshan <jiangshanlai@gmail.com>
Cc: Zqiang <qiang1.zhang@intel.com>
---
 include/linux/rcupdate.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index dcd2cf1e8326..38e84f3d515e 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -430,16 +430,16 @@ static inline void rcu_preempt_sleep_check(void) { }
 
 #ifdef __CHECKER__
 #define rcu_check_sparse(p, space) \
-	((void)(((typeof(*p) space *)p) == p))
+	((void)(((typeof(*(p)) space *)(p)) == (p)))
 #else /* #ifdef __CHECKER__ */
 #define rcu_check_sparse(p, space)
 #endif /* #else #ifdef __CHECKER__ */
 
 #define __unrcu_pointer(p, local)					\
 ({									\
-	typeof(*p) *local = (typeof(*p) *__force)(p);			\
+	typeof(*(p)) *local = (typeof(*(p)) *__force)(p);		\
 	rcu_check_sparse(p, __rcu);					\
-	((typeof(*p) __force __kernel *)(local)); 			\
+	((typeof(*(p)) __force __kernel *)(local));			\
 })
 /**
  * unrcu_pointer - mark a pointer as not being RCU protected
@@ -452,29 +452,29 @@ static inline void rcu_preempt_sleep_check(void) { }
 
 #define __rcu_access_pointer(p, local, space) \
 ({ \
-	typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
+	typeof(*(p)) *local = (typeof(*(p)) *__force)READ_ONCE(p); \
 	rcu_check_sparse(p, space); \
-	((typeof(*p) __force __kernel *)(local)); \
+	((typeof(*(p)) __force __kernel *)(local)); \
 })
 #define __rcu_dereference_check(p, local, c, space) \
 ({ \
 	/* Dependency order vs. p above. */ \
-	typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
+	typeof(*(p)) *local = (typeof(*(p)) *__force)READ_ONCE(p); \
 	RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \
 	rcu_check_sparse(p, space); \
-	((typeof(*p) __force __kernel *)(local)); \
+	((typeof(*(p)) __force __kernel *)(local)); \
 })
 #define __rcu_dereference_protected(p, local, c, space) \
 ({ \
 	RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_protected() usage"); \
 	rcu_check_sparse(p, space); \
-	((typeof(*p) __force __kernel *)(p)); \
+	((typeof(*(p)) __force __kernel *)(p)); \
 })
 #define __rcu_dereference_raw(p, local) \
 ({ \
 	/* Dependency order vs. p above. */ \
 	typeof(p) local = READ_ONCE(p); \
-	((typeof(*p) __force __kernel *)(local)); \
+	((typeof(*(p)) __force __kernel *)(local)); \
 })
 #define rcu_dereference_raw(p) __rcu_dereference_raw(p, __UNIQUE_ID(rcu))
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 [RFC PATCH 1/4] rcu: rcupdate.h: Add missing parentheses around macro pointer dereference Mathieu Desnoyers
@ 2023-05-04  1:29 ` Mathieu Desnoyers
  2023-05-04 14:41   ` Andy Shevchenko
  2023-05-04  1:29 ` [RFC PATCH 3/4] rculist.h: " Mathieu Desnoyers
  2023-05-04  1:29 ` [RFC PATCH 4/4] llist.h: " Mathieu Desnoyers
  2 siblings, 1 reply; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04  1:29 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, Mathieu Desnoyers, Greg Kroah-Hartman,
	Andy Shevchenko, David Howells, Ricardo Martinez

Add missing parentheses around use of macro argument "pos" in those
patterns to ensure operator precedence behaves as expected:

- typeof(*pos)
- pos->member

Remove useless parentheses around use of macro parameter (head) in the
following pattern:

- list_is_head(pos, (head))

Because comma is the lowest priority operator already, so the extra pair
of parentheses is redundant.

This corrects the following usage pattern where operator precedence is
unexpected:

  LIST_HEAD(testlist);

  struct test {
          struct list_head node;
          int a;
  };

  // pos->member issue
  void f(void)
  {
          struct test *t1;
          struct test **t2 = &t1;

          list_for_each_entry((*t2), &testlist, node) {   /* works */
                  //...
          }
          list_for_each_entry(*t2, &testlist, node) {     /* broken */
                  //...
          }
  }

  // typeof(*pos) issue
  void f2(void)
  {
          struct test *t1 = NULL, *t2;

          t2 = list_prepare_entry((0 + t1), &testlist, node);     /* works */
          t2 = list_prepare_entry(0 + t1, &testlist, node);       /* broken */
  }

Note that the macros in which "pos" is also used as an lvalue probably
don't suffer from the lack of parentheses around "pos" in typeof(*pos),
but add those nevertheless to keep everything consistent.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Ricardo Martinez <ricardo.martinez@linux.intel.com>
---
 include/linux/list.h | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index f10344dbad4d..bb106238eaf6 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -603,7 +603,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each(pos, head) \
-	for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
+	for (pos = (head)->next; !list_is_head(pos, head); pos = (pos)->next)
 
 /**
  * list_for_each_rcu - Iterate over a list in an RCU-safe fashion
@@ -612,8 +612,8 @@ static inline void list_splice_tail_init(struct list_head *list,
  */
 #define list_for_each_rcu(pos, head)		  \
 	for (pos = rcu_dereference((head)->next); \
-	     !list_is_head(pos, (head)); \
-	     pos = rcu_dereference(pos->next))
+	     !list_is_head(pos, head); \
+	     pos = rcu_dereference((pos)->next))
 
 /**
  * list_for_each_continue - continue iteration over a list
@@ -623,7 +623,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * Continue to iterate over a list, continuing after the current position.
  */
 #define list_for_each_continue(pos, head) \
-	for (pos = pos->next; !list_is_head(pos, (head)); pos = pos->next)
+	for (pos = (pos)->next; !list_is_head(pos, head); pos = (pos)->next)
 
 /**
  * list_for_each_prev	-	iterate over a list backwards
@@ -631,7 +631,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each_prev(pos, head) \
-	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
+	for (pos = (head)->prev; !list_is_head(pos, head); pos = (pos)->prev)
 
 /**
  * list_for_each_safe - iterate over a list safe against removal of list entry
@@ -640,9 +640,9 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each_safe(pos, n, head) \
-	for (pos = (head)->next, n = pos->next; \
-	     !list_is_head(pos, (head)); \
-	     pos = n, n = pos->next)
+	for (pos = (head)->next, n = (pos)->next; \
+	     !list_is_head(pos, head); \
+	     pos = n, n = (pos)->next)
 
 /**
  * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
@@ -651,9 +651,9 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each_prev_safe(pos, n, head) \
-	for (pos = (head)->prev, n = pos->prev; \
-	     !list_is_head(pos, (head)); \
-	     pos = n, n = pos->prev)
+	for (pos = (head)->prev, n = (pos)->prev; \
+	     !list_is_head(pos, head); \
+	     pos = n, n = (pos)->prev)
 
 /**
  * list_count_nodes - count nodes in the list
@@ -677,7 +677,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * @member:	the name of the list_head within the struct.
  */
 #define list_entry_is_head(pos, head, member)				\
-	(&pos->member == (head))
+	(&(pos)->member == (head))
 
 /**
  * list_for_each_entry	-	iterate over list of given type
@@ -686,7 +686,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry(pos, head, member)				\
-	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	for (pos = list_first_entry(head, typeof(*(pos)), member);	\
 	     !list_entry_is_head(pos, head, member);			\
 	     pos = list_next_entry(pos, member))
 
@@ -697,7 +697,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry_reverse(pos, head, member)			\
-	for (pos = list_last_entry(head, typeof(*pos), member);		\
+	for (pos = list_last_entry(head, typeof(*(pos)), member);	\
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = list_prev_entry(pos, member))
 
@@ -710,7 +710,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
  */
 #define list_prepare_entry(pos, head, member) \
-	((pos) ? : list_entry(head, typeof(*pos), member))
+	((pos) ? : list_entry(head, typeof(*(pos)), member))
 
 /**
  * list_for_each_entry_continue - continue iteration over list of given type
@@ -773,7 +773,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
-	for (pos = list_first_entry(head, typeof(*pos), member),	\
+	for (pos = list_first_entry(head, typeof(*(pos)), member),	\
 		n = list_next_entry(pos, member);			\
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_next_entry(n, member))
@@ -820,7 +820,7 @@ static inline size_t list_count_nodes(struct list_head *head)
  * of list entry.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
-	for (pos = list_last_entry(head, typeof(*pos), member),		\
+	for (pos = list_last_entry(head, typeof(*(pos)), member),	\
 		n = list_prev_entry(pos, member);			\
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_prev_entry(n, member))
@@ -1033,10 +1033,10 @@ static inline void hlist_move_list(struct hlist_head *old,
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
-	for (pos = (head)->first; pos ; pos = pos->next)
+	for (pos = (head)->first; pos ; pos = (pos)->next)
 
 #define hlist_for_each_safe(pos, n, head) \
-	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	for (pos = (head)->first; pos && ({ n = (pos)->next; 1; }); \
 	     pos = n)
 
 #define hlist_entry_safe(ptr, type, member) \
@@ -1082,8 +1082,8 @@ static inline void hlist_move_list(struct hlist_head *old,
  * @member:	the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_safe(pos, n, head, member) 		\
-	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
-	     pos && ({ n = pos->member.next; 1; });			\
-	     pos = hlist_entry_safe(n, typeof(*pos), member))
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+	     pos && ({ n = (pos)->member.next; 1; });			\
+	     pos = hlist_entry_safe(n, typeof(*(pos)), member))
 
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 3/4] rculist.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 [RFC PATCH 1/4] rcu: rcupdate.h: Add missing parentheses around macro pointer dereference Mathieu Desnoyers
  2023-05-04  1:29 ` [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use Mathieu Desnoyers
@ 2023-05-04  1:29 ` Mathieu Desnoyers
  2023-05-04 16:19   ` Joel Fernandes
  2023-05-04  1:29 ` [RFC PATCH 4/4] llist.h: " Mathieu Desnoyers
  2 siblings, 1 reply; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04  1:29 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, Mathieu Desnoyers, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Josh Triplett, Boqun Feng, Steven Rostedt, Lai Jiangshan, Zqiang,
	rcu

Add missing parentheses around use of macro argument "pos" in those
patterns to ensure operator precedence behaves as expected:

- typeof(*pos)
- pos->member

This corrects the following usage pattern where operator precedence is
unexpected:

  LIST_HEAD(testlist);

  struct test {
          struct list_head node;
          int a;
  };

  // pos->member issue
  void f(void)
  {
          struct test *t1;
          struct test **t2 = &t1;

          list_for_each_entry_rcu((*t2), &testlist, node) {       /* works */
                  //...
          }
          list_for_each_entry_rcu(*t2, &testlist, node) { /* broken */
                  //...
          }
  }

The typeof(*pos) lack of parentheses around "pos" is not an issue per se
in the specific macros modified here because "pos" is used as an lvalue,
which should prevent use of any operator causing issue. Still add the
extra parentheses for consistency.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Frederic Weisbecker <frederic@kernel.org>
Cc: Neeraj Upadhyay <quic_neeraju@quicinc.com>
Cc: Joel Fernandes <joel@joelfernandes.org>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Lai Jiangshan <jiangshanlai@gmail.com>
Cc: Zqiang <qiang1.zhang@intel.com>
Cc: rcu@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
 include/linux/rculist.h | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index d29740be4833..d27aeff5447d 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -388,9 +388,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  */
 #define list_for_each_entry_rcu(pos, head, member, cond...)		\
 	for (__list_check_rcu(dummy, ## cond, 0),			\
-	     pos = list_entry_rcu((head)->next, typeof(*pos), member);	\
-		&pos->member != (head);					\
-		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
+	     pos = list_entry_rcu((head)->next, typeof(*(pos)), member);\
+		&(pos)->member != (head);				\
+		pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
 
 /**
  * list_for_each_entry_srcu	-	iterate over rcu list of given type
@@ -407,9 +407,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  */
 #define list_for_each_entry_srcu(pos, head, member, cond)		\
 	for (__list_check_srcu(cond),					\
-	     pos = list_entry_rcu((head)->next, typeof(*pos), member);	\
-		&pos->member != (head);					\
-		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
+	     pos = list_entry_rcu((head)->next, typeof(*(pos)), member);\
+		&(pos)->member != (head);				\
+		pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
 
 /**
  * list_entry_lockless - get the struct for this entry
@@ -441,9 +441,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  * but never deleted.
  */
 #define list_for_each_entry_lockless(pos, head, member) \
-	for (pos = list_entry_lockless((head)->next, typeof(*pos), member); \
-	     &pos->member != (head); \
-	     pos = list_entry_lockless(pos->member.next, typeof(*pos), member))
+	for (pos = list_entry_lockless((head)->next, typeof(*(pos)), member); \
+	     &(pos)->member != (head); \
+	     pos = list_entry_lockless((pos)->member.next, typeof(*(pos)), member))
 
 /**
  * list_for_each_entry_continue_rcu - continue iteration over list of given type
@@ -464,9 +464,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  * position.
  */
 #define list_for_each_entry_continue_rcu(pos, head, member) 		\
-	for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \
-	     &pos->member != (head);	\
-	     pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
+	for (pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member); \
+	     &(pos)->member != (head);	\
+	     pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
 
 /**
  * list_for_each_entry_from_rcu - iterate over a list from current point
@@ -486,8 +486,8 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
  * after the given position.
  */
 #define list_for_each_entry_from_rcu(pos, head, member)			\
-	for (; &(pos)->member != (head);					\
-		pos = list_entry_rcu(pos->member.next, typeof(*(pos)), member))
+	for (; &(pos)->member != (head);				\
+		pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
 
 /**
  * hlist_del_rcu - deletes entry from hash list without re-initialization
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 [RFC PATCH 1/4] rcu: rcupdate.h: Add missing parentheses around macro pointer dereference Mathieu Desnoyers
  2023-05-04  1:29 ` [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use Mathieu Desnoyers
  2023-05-04  1:29 ` [RFC PATCH 3/4] rculist.h: " Mathieu Desnoyers
@ 2023-05-04  1:29 ` Mathieu Desnoyers
  2023-05-04  5:54   ` Huang, Ying
  2 siblings, 1 reply; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04  1:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, Mathieu Desnoyers, Huang Ying, Peter Zijlstra

Add missing parentheses around use of macro argument "pos" in those
patterns to ensure operator precedence behaves as expected:

- typeof(*pos)
- pos->member

The typeof(*pos) lack of parentheses around "pos" is not an issue per se
in the specific macros modified here because "pos" is used as an lvalue,
which should prevent use of any operator causing issue. Still add the
extra parentheses for consistency.

Remove useless parentheses around use of macro parameter (node) in the
following pattern:

  llist_entry((node), typeof(*pos), member)

Because comma is the lowest priority operator already, so the extra pair
of parentheses is redundant.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/llist.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index 85bda2d02d65..45d358c15d0d 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -173,9 +173,9 @@ static inline void init_llist_head(struct llist_head *list)
  * reverse the order by yourself before traversing.
  */
 #define llist_for_each_entry_safe(pos, n, node, member)			       \
-	for (pos = llist_entry((node), typeof(*pos), member);		       \
+	for (pos = llist_entry(node, typeof(*(pos)), member);		       \
 	     member_address_is_nonnull(pos, member) &&			       \
-	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
+		(n = llist_entry((pos)->member.next, typeof(*(n)), member), true); \
 	     pos = n)
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 ` [RFC PATCH 4/4] llist.h: " Mathieu Desnoyers
@ 2023-05-04  5:54   ` Huang, Ying
  2023-05-04 14:54     ` Mathieu Desnoyers
  0 siblings, 1 reply; 17+ messages in thread
From: Huang, Ying @ 2023-05-04  5:54 UTC (permalink / raw)
  To: Mathieu Desnoyers; +Cc: Andrew Morton, linux-kernel, Peter Zijlstra

Hi, Mathieu,

Mathieu Desnoyers <mathieu.desnoyers@efficios.com> writes:

> Add missing parentheses around use of macro argument "pos" in those
> patterns to ensure operator precedence behaves as expected:
>
> - typeof(*pos)
> - pos->member
>
> The typeof(*pos) lack of parentheses around "pos" is not an issue per se
> in the specific macros modified here because "pos" is used as an lvalue,
> which should prevent use of any operator causing issue. Still add the
> extra parentheses for consistency.

I don't think it's necessary to add parentheses here.  As you said,
"pos" is used as an lvalue.

> Remove useless parentheses around use of macro parameter (node) in the
> following pattern:
>
>   llist_entry((node), typeof(*pos), member)
>
> Because comma is the lowest priority operator already, so the extra pair
> of parentheses is redundant.

This change looks good for me.

Best Regards,
Huang, Ying

> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Huang Ying <ying.huang@intel.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> ---
>  include/linux/llist.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/llist.h b/include/linux/llist.h
> index 85bda2d02d65..45d358c15d0d 100644
> --- a/include/linux/llist.h
> +++ b/include/linux/llist.h
> @@ -173,9 +173,9 @@ static inline void init_llist_head(struct llist_head *list)
>   * reverse the order by yourself before traversing.
>   */
>  #define llist_for_each_entry_safe(pos, n, node, member)			       \
> -	for (pos = llist_entry((node), typeof(*pos), member);		       \
> +	for (pos = llist_entry(node, typeof(*(pos)), member);		       \
>  	     member_address_is_nonnull(pos, member) &&			       \
> -	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
> +		(n = llist_entry((pos)->member.next, typeof(*(n)), member), true); \
>  	     pos = n)
>  
>  /**

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 ` [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use Mathieu Desnoyers
@ 2023-05-04 14:41   ` Andy Shevchenko
  2023-05-04 14:45     ` Mathieu Desnoyers
  0 siblings, 1 reply; 17+ messages in thread
From: Andy Shevchenko @ 2023-05-04 14:41 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Andrew Morton, linux-kernel, Greg Kroah-Hartman, David Howells,
	Ricardo Martinez

On Wed, May 03, 2023 at 09:29:12PM -0400, Mathieu Desnoyers wrote:
> Add missing parentheses around use of macro argument "pos" in those
> patterns to ensure operator precedence behaves as expected:
> 
> - typeof(*pos)
> - pos->member
> 
> Remove useless parentheses around use of macro parameter (head) in the
> following pattern:
> 
> - list_is_head(pos, (head))
> 
> Because comma is the lowest priority operator already, so the extra pair
> of parentheses is redundant.
> 
> This corrects the following usage pattern where operator precedence is
> unexpected:
> 
>   LIST_HEAD(testlist);
> 
>   struct test {
>           struct list_head node;
>           int a;
>   };
> 
>   // pos->member issue
>   void f(void)
>   {
>           struct test *t1;
>           struct test **t2 = &t1;

I'm not against the patch, but I'm in doubt, looking into this example, it's useful.
Any real use case like above in the Linux kernel, please?

>           list_for_each_entry((*t2), &testlist, node) {   /* works */
>                   //...
>           }
>           list_for_each_entry(*t2, &testlist, node) {     /* broken */
>                   //...
>           }
>   }

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use
  2023-05-04 14:41   ` Andy Shevchenko
@ 2023-05-04 14:45     ` Mathieu Desnoyers
  0 siblings, 0 replies; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04 14:45 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Andrew Morton, linux-kernel, Greg Kroah-Hartman, David Howells,
	Ricardo Martinez

On 2023-05-04 10:41, Andy Shevchenko wrote:
> On Wed, May 03, 2023 at 09:29:12PM -0400, Mathieu Desnoyers wrote:
>> Add missing parentheses around use of macro argument "pos" in those
>> patterns to ensure operator precedence behaves as expected:
>>
>> - typeof(*pos)
>> - pos->member
>>
>> Remove useless parentheses around use of macro parameter (head) in the
>> following pattern:
>>
>> - list_is_head(pos, (head))
>>
>> Because comma is the lowest priority operator already, so the extra pair
>> of parentheses is redundant.
>>
>> This corrects the following usage pattern where operator precedence is
>> unexpected:
>>
>>    LIST_HEAD(testlist);
>>
>>    struct test {
>>            struct list_head node;
>>            int a;
>>    };
>>
>>    // pos->member issue
>>    void f(void)
>>    {
>>            struct test *t1;
>>            struct test **t2 = &t1;
> 
> I'm not against the patch, but I'm in doubt, looking into this example, it's useful.
> Any real use case like above in the Linux kernel, please?

There aren't because the code would not compile with the current header 
implementation. But it's unexpected that this kind of pattern does not work.

It's not about being useful, but rather about eliminating unexpected 
operator precedence within macros, and about being consistent everywhere.

Thanks,

Mathieu

> 
>>            list_for_each_entry((*t2), &testlist, node) {   /* works */
>>                    //...
>>            }
>>            list_for_each_entry(*t2, &testlist, node) {     /* broken */
>>                    //...
>>            }
>>    }
> 

-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04  5:54   ` Huang, Ying
@ 2023-05-04 14:54     ` Mathieu Desnoyers
  2023-05-04 17:16       ` Linus Torvalds
  0 siblings, 1 reply; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-04 14:54 UTC (permalink / raw)
  To: Huang, Ying; +Cc: Andrew Morton, linux-kernel, Peter Zijlstra, Linus Torvalds

On 2023-05-04 01:54, Huang, Ying wrote:
> Hi, Mathieu,
> 
> Mathieu Desnoyers <mathieu.desnoyers@efficios.com> writes:
> 
>> Add missing parentheses around use of macro argument "pos" in those
>> patterns to ensure operator precedence behaves as expected:
>>
>> - typeof(*pos)
>> - pos->member
>>
>> The typeof(*pos) lack of parentheses around "pos" is not an issue per se
>> in the specific macros modified here because "pos" is used as an lvalue,
>> which should prevent use of any operator causing issue. Still add the
>> extra parentheses for consistency.
> 
> I don't think it's necessary to add parentheses here.  As you said,
> "pos" is used as an lvalue.

I agree that it's not strictly necessary to add the parentheses around
"pos" in typeof(*pos) when pos is also used as an lvalue within a macro,
but if we look at what happened in list.h, we can see why having a consistent
pattern is good to eliminate issues as the code evolves.

When code from list_for_each_entry_continue was lifted into
list_prepare_entry(), we had a situation where "pos" was initially used
as an lvalue in the original macro, but not in list_prepare_entry(), for
which the parentheses were relevant.

This example is from the pre-git era, in tglx's history tree:

commit a3500b9e955d47891e57587c30006de83a3591f5
Author: Linus Torvalds <torvalds@home.osdl.org>
Date:   Wed Feb 11 21:00:34 2004 -0800

     Fix "bus_for_each_dev()" and "bus_for_each_drv()", which did not
     correctly handle the "restart from this device/driver" case, and
     caused oopses with ieee1394.
     
     This just uses "list_for_each_entry_continue()" instead.
     
     Add helper macro to make usage of "list_for_each_entry_continue()"
     a bit more readable.

[...]

+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ *                     list_for_each_entry_continue
+ * @pos:       the type * to use as a start point
+ * @head:      the head of the list
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+       ((pos) ? : list_entry(head, typeof(*pos), member))

So even though the fact that "pos" is used as an lvalue specifically in
llist_for_each_entry_safe() makes it so that the parentheses are not
strictly required around "pos" in typeof(*pos), I argue that we should
still add those for consistency.

> 
>> Remove useless parentheses around use of macro parameter (node) in the
>> following pattern:
>>
>>    llist_entry((node), typeof(*pos), member)
>>
>> Because comma is the lowest priority operator already, so the extra pair
>> of parentheses is redundant.
> 
> This change looks good for me.

Thanks,

Mathieu

> 
> Best Regards,
> Huang, Ying
> 
>> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> Cc: Huang Ying <ying.huang@intel.com>
>> Cc: Peter Zijlstra <peterz@infradead.org>
>> ---
>>   include/linux/llist.h | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/llist.h b/include/linux/llist.h
>> index 85bda2d02d65..45d358c15d0d 100644
>> --- a/include/linux/llist.h
>> +++ b/include/linux/llist.h
>> @@ -173,9 +173,9 @@ static inline void init_llist_head(struct llist_head *list)
>>    * reverse the order by yourself before traversing.
>>    */
>>   #define llist_for_each_entry_safe(pos, n, node, member)			       \
>> -	for (pos = llist_entry((node), typeof(*pos), member);		       \
>> +	for (pos = llist_entry(node, typeof(*(pos)), member);		       \
>>   	     member_address_is_nonnull(pos, member) &&			       \
>> -	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
>> +		(n = llist_entry((pos)->member.next, typeof(*(n)), member), true); \
>>   	     pos = n)
>>   
>>   /**

-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 3/4] rculist.h: Fix parentheses around macro pointer parameter use
  2023-05-04  1:29 ` [RFC PATCH 3/4] rculist.h: " Mathieu Desnoyers
@ 2023-05-04 16:19   ` Joel Fernandes
  2023-05-05 14:06     ` Steven Rostedt
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Fernandes @ 2023-05-04 16:19 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Andrew Morton, linux-kernel, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Josh Triplett, Boqun Feng,
	Steven Rostedt, Lai Jiangshan, Zqiang, rcu

Hello Mathieu,

On Wed, May 3, 2023 at 9:29 PM Mathieu Desnoyers
<mathieu.desnoyers@efficios.com> wrote:
>
> Add missing parentheses around use of macro argument "pos" in those
> patterns to ensure operator precedence behaves as expected:
>
> - typeof(*pos)
> - pos->member
>
> This corrects the following usage pattern where operator precedence is
> unexpected:
>
>   LIST_HEAD(testlist);
>
>   struct test {
>           struct list_head node;
>           int a;
>   };
>
>   // pos->member issue
>   void f(void)
>   {
>           struct test *t1;
>           struct test **t2 = &t1;
>
>           list_for_each_entry_rcu((*t2), &testlist, node) {       /* works */
>                   //...
>           }
>           list_for_each_entry_rcu(*t2, &testlist, node) { /* broken */
>                   //...
>           }

Yeah it is not clear why anyone would ever want to use it like this.
Why don't they just pass t1 to list_for_each_entry_rcu() ? I would
rather it break them and they re-think their code ;).

>   }
>
> The typeof(*pos) lack of parentheses around "pos" is not an issue per se
> in the specific macros modified here because "pos" is used as an lvalue,
> which should prevent use of any operator causing issue. Still add the
> extra parentheses for consistency.

The consistency argument is valid though.  I will stay neutral on this
patch. ;-)

thanks!

 - Joel



>
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: "Paul E. McKenney" <paulmck@kernel.org>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Frederic Weisbecker <frederic@kernel.org>
> Cc: Neeraj Upadhyay <quic_neeraju@quicinc.com>
> Cc: Joel Fernandes <joel@joelfernandes.org>
> Cc: Josh Triplett <josh@joshtriplett.org>
> Cc: Boqun Feng <boqun.feng@gmail.com>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Lai Jiangshan <jiangshanlai@gmail.com>
> Cc: Zqiang <qiang1.zhang@intel.com>
> Cc: rcu@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  include/linux/rculist.h | 28 ++++++++++++++--------------
>  1 file changed, 14 insertions(+), 14 deletions(-)
>
> diff --git a/include/linux/rculist.h b/include/linux/rculist.h
> index d29740be4833..d27aeff5447d 100644
> --- a/include/linux/rculist.h
> +++ b/include/linux/rculist.h
> @@ -388,9 +388,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
>   */
>  #define list_for_each_entry_rcu(pos, head, member, cond...)            \
>         for (__list_check_rcu(dummy, ## cond, 0),                       \
> -            pos = list_entry_rcu((head)->next, typeof(*pos), member);  \
> -               &pos->member != (head);                                 \
> -               pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
> +            pos = list_entry_rcu((head)->next, typeof(*(pos)), member);\
> +               &(pos)->member != (head);                               \
> +               pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
>
>  /**
>   * list_for_each_entry_srcu    -       iterate over rcu list of given type
> @@ -407,9 +407,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
>   */
>  #define list_for_each_entry_srcu(pos, head, member, cond)              \
>         for (__list_check_srcu(cond),                                   \
> -            pos = list_entry_rcu((head)->next, typeof(*pos), member);  \
> -               &pos->member != (head);                                 \
> -               pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
> +            pos = list_entry_rcu((head)->next, typeof(*(pos)), member);\
> +               &(pos)->member != (head);                               \
> +               pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
>
>  /**
>   * list_entry_lockless - get the struct for this entry
> @@ -441,9 +441,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
>   * but never deleted.
>   */
>  #define list_for_each_entry_lockless(pos, head, member) \
> -       for (pos = list_entry_lockless((head)->next, typeof(*pos), member); \
> -            &pos->member != (head); \
> -            pos = list_entry_lockless(pos->member.next, typeof(*pos), member))
> +       for (pos = list_entry_lockless((head)->next, typeof(*(pos)), member); \
> +            &(pos)->member != (head); \
> +            pos = list_entry_lockless((pos)->member.next, typeof(*(pos)), member))
>
>  /**
>   * list_for_each_entry_continue_rcu - continue iteration over list of given type
> @@ -464,9 +464,9 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
>   * position.
>   */
>  #define list_for_each_entry_continue_rcu(pos, head, member)            \
> -       for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \
> -            &pos->member != (head);    \
> -            pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
> +       for (pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member); \
> +            &(pos)->member != (head);  \
> +            pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
>
>  /**
>   * list_for_each_entry_from_rcu - iterate over a list from current point
> @@ -486,8 +486,8 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
>   * after the given position.
>   */
>  #define list_for_each_entry_from_rcu(pos, head, member)                        \
> -       for (; &(pos)->member != (head);                                        \
> -               pos = list_entry_rcu(pos->member.next, typeof(*(pos)), member))
> +       for (; &(pos)->member != (head);                                \
> +               pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
>
>  /**
>   * hlist_del_rcu - deletes entry from hash list without re-initialization
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04 14:54     ` Mathieu Desnoyers
@ 2023-05-04 17:16       ` Linus Torvalds
  2023-05-05  1:38         ` Huang, Ying
  2023-05-05 14:23         ` Mathieu Desnoyers
  0 siblings, 2 replies; 17+ messages in thread
From: Linus Torvalds @ 2023-05-04 17:16 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Huang, Ying, Andrew Morton, linux-kernel, Peter Zijlstra

On Thu, May 4, 2023 at 7:54 AM Mathieu Desnoyers
<mathieu.desnoyers@efficios.com> wrote:
> +#define list_prepare_entry(pos, head, member) \
> +       ((pos) ? : list_entry(head, typeof(*pos), member))
>
> So even though the fact that "pos" is used as an lvalue specifically in
> llist_for_each_entry_safe() makes it so that the parentheses are not
> strictly required around "pos" in typeof(*pos), I argue that we should
> still add those for consistency.

Ack. It may not matter in reality because of how 'pos' is supposed to
be just a local variable name, but I agree that for consistency our
macros should still follow the usual pattern.

Of course, *because* of how 'pos' is not some random expression, and
is supposed to be that local variable, and because of how it is used,
it must always violate the whole "only use once" usual pattern,.

Exactly the same way the member name is also typically used multiple
times because of how it's not an expression, but really a "part of the
syntax".

So an alternative might be that we should use a different syntax for
those things and make it clear that they are not normal expressions.
Some people use upper-case names for special things like that to make
them stand out as "not normal" (kind of the same way upper-case macros
themselves were a warning that they weren't normal and might evaluate
arguments multiple times).

                   Linus

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04 17:16       ` Linus Torvalds
@ 2023-05-05  1:38         ` Huang, Ying
  2023-05-05 14:23         ` Mathieu Desnoyers
  1 sibling, 0 replies; 17+ messages in thread
From: Huang, Ying @ 2023-05-05  1:38 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Mathieu Desnoyers, Andrew Morton, linux-kernel, Peter Zijlstra

Linus Torvalds <torvalds@linux-foundation.org> writes:

> On Thu, May 4, 2023 at 7:54 AM Mathieu Desnoyers
> <mathieu.desnoyers@efficios.com> wrote:
>> +#define list_prepare_entry(pos, head, member) \
>> +       ((pos) ? : list_entry(head, typeof(*pos), member))
>>
>> So even though the fact that "pos" is used as an lvalue specifically in
>> llist_for_each_entry_safe() makes it so that the parentheses are not
>> strictly required around "pos" in typeof(*pos), I argue that we should
>> still add those for consistency.
>
> Ack. It may not matter in reality because of how 'pos' is supposed to
> be just a local variable name, but I agree that for consistency our
> macros should still follow the usual pattern.
>
> Of course, *because* of how 'pos' is not some random expression, and
> is supposed to be that local variable, and because of how it is used,
> it must always violate the whole "only use once" usual pattern,.
>
> Exactly the same way the member name is also typically used multiple
> times because of how it's not an expression, but really a "part of the
> syntax".
>
> So an alternative might be that we should use a different syntax for
> those things and make it clear that they are not normal expressions.
> Some people use upper-case names for special things like that to make
> them stand out as "not normal" (kind of the same way upper-case macros
> themselves were a warning that they weren't normal and might evaluate
> arguments multiple times).

This sounds a good idea for me.

And with this, I think that we will use typeof(*POS) instead of
typeof(*(pos))?

Best Regards,
Huang, Ying

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 3/4] rculist.h: Fix parentheses around macro pointer parameter use
  2023-05-04 16:19   ` Joel Fernandes
@ 2023-05-05 14:06     ` Steven Rostedt
  2023-05-05 14:35       ` Joel Fernandes
  0 siblings, 1 reply; 17+ messages in thread
From: Steven Rostedt @ 2023-05-05 14:06 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: Mathieu Desnoyers, Andrew Morton, linux-kernel, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Josh Triplett, Boqun Feng,
	Lai Jiangshan, Zqiang, rcu

On Thu, 4 May 2023 12:19:38 -0400
Joel Fernandes <joel@joelfernandes.org> wrote:

> >   void f(void)
> >   {
> >           struct test *t1;
> >           struct test **t2 = &t1;
> >
> >           list_for_each_entry_rcu((*t2), &testlist, node) {       /* works */
> >                   //...
> >           }
> >           list_for_each_entry_rcu(*t2, &testlist, node) { /* broken */
> >                   //...
> >           }  
> 
> Yeah it is not clear why anyone would ever want to use it like this.
> Why don't they just pass t1 to list_for_each_entry_rcu() ? I would
> rather it break them and they re-think their code ;).

Remember interfaces should not be enforcing policy unless it's key to the
way the interface works.

-- Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-04 17:16       ` Linus Torvalds
  2023-05-05  1:38         ` Huang, Ying
@ 2023-05-05 14:23         ` Mathieu Desnoyers
  2023-05-05 18:08           ` Linus Torvalds
  2023-05-06  1:12           ` Huang, Ying
  1 sibling, 2 replies; 17+ messages in thread
From: Mathieu Desnoyers @ 2023-05-05 14:23 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Huang, Ying, Andrew Morton, linux-kernel, Peter Zijlstra

On 2023-05-04 13:16, Linus Torvalds wrote:
> On Thu, May 4, 2023 at 7:54 AM Mathieu Desnoyers
> <mathieu.desnoyers@efficios.com> wrote:
>> +#define list_prepare_entry(pos, head, member) \
>> +       ((pos) ? : list_entry(head, typeof(*pos), member))
>>
>> So even though the fact that "pos" is used as an lvalue specifically in
>> llist_for_each_entry_safe() makes it so that the parentheses are not
>> strictly required around "pos" in typeof(*pos), I argue that we should
>> still add those for consistency.
> 
> Ack. It may not matter in reality because of how 'pos' is supposed to
> be just a local variable name, but I agree that for consistency our
> macros should still follow the usual pattern.
> 
> Of course, *because* of how 'pos' is not some random expression, and
> is supposed to be that local variable, and because of how it is used,
> it must always violate the whole "only use once" usual pattern,.
> 
> Exactly the same way the member name is also typically used multiple
> times because of how it's not an expression, but really a "part of the
> syntax".
> 
> So an alternative might be that we should use a different syntax for
> those things and make it clear that they are not normal expressions.
> Some people use upper-case names for special things like that to make
> them stand out as "not normal" (kind of the same way upper-case macros
> themselves were a warning that they weren't normal and might evaluate
> arguments multiple times).

Is a list iteration position absolutely required to be a local variable,
or can it be a dereferenced pointer ?

Let's say we take "list_for_each()" as example:

#define list_for_each(pos, head) \
         for (pos = (head)->next; !list_is_head(pos, head); pos = pos->next)

and turn "pos" into "POS" to make it clearer that it is used as an lvalue:

#define list_for_each(POS, head) \
         for (POS = (head)->next; !list_is_head(POS, head); pos = POS->next)

The following usage pattern is still broken:

struct list_head list;

void f(struct list_head **ppos)
{
   list_for_each(*ppos, &list) {
     //...
   }
}

Because ->next has higher operator precedence than "*", which is unexpected.

I would argue that even if we choose to capitalize the macro special arguments used
as lvalues and as member names so they stand out, it does not eliminate the need to
be careful about proper use of parentheses around those parameters when they are also
used as rvalues.

Thanks,

Mathieu

-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 3/4] rculist.h: Fix parentheses around macro pointer parameter use
  2023-05-05 14:06     ` Steven Rostedt
@ 2023-05-05 14:35       ` Joel Fernandes
  2023-05-05 15:02         ` Steven Rostedt
  0 siblings, 1 reply; 17+ messages in thread
From: Joel Fernandes @ 2023-05-05 14:35 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Mathieu Desnoyers, Andrew Morton, linux-kernel, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Josh Triplett, Boqun Feng,
	Lai Jiangshan, Zqiang, rcu



> On May 5, 2023, at 10:06 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> On Thu, 4 May 2023 12:19:38 -0400
> Joel Fernandes <joel@joelfernandes.org> wrote:
> 
>>>  void f(void)
>>>  {
>>>          struct test *t1;
>>>          struct test **t2 = &t1;
>>> 
>>>          list_for_each_entry_rcu((*t2), &testlist, node) {       /* works */
>>>                  //...
>>>          }
>>>          list_for_each_entry_rcu(*t2, &testlist, node) { /* broken */
>>>                  //...
>>>          }  
>> 
>> Yeah it is not clear why anyone would ever want to use it like this.
>> Why don't they just pass t1 to list_for_each_entry_rcu() ? I would
>> rather it break them and they re-think their code ;).
> 
> Remember interfaces should not be enforcing policy unless it's key to the
> way the interface works.

Oh yeah, 100% agree. I am not particularly against this particular patch but I also dont see it as solving any problem. Feel free to Ack the patch if you feel strongly about wanting it.

 - Joel


> 
> -- Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 3/4] rculist.h: Fix parentheses around macro pointer parameter use
  2023-05-05 14:35       ` Joel Fernandes
@ 2023-05-05 15:02         ` Steven Rostedt
  0 siblings, 0 replies; 17+ messages in thread
From: Steven Rostedt @ 2023-05-05 15:02 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: Mathieu Desnoyers, Andrew Morton, linux-kernel, Paul E. McKenney,
	Frederic Weisbecker, Neeraj Upadhyay, Josh Triplett, Boqun Feng,
	Lai Jiangshan, Zqiang, rcu

On Fri, 5 May 2023 10:35:39 -0400
Joel Fernandes <joel@joelfernandes.org> wrote:

> >> Yeah it is not clear why anyone would ever want to use it like this.
> >> Why don't they just pass t1 to list_for_each_entry_rcu() ? I would
> >> rather it break them and they re-think their code ;).  
> > 
> > Remember interfaces should not be enforcing policy unless it's key to the
> > way the interface works.  
> 
> Oh yeah, 100% agree. I am not particularly against this particular patch
> but I also dont see it as solving any problem. Feel free to Ack the patch
> if you feel strongly about wanting it.

I agree that this isn't solving any real bugs, but it is a legitimate
cleanup.

And as someone that tends to push interfaces to their limits, I would
likely be the one that hits it ;-)

Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>

-- Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-05 14:23         ` Mathieu Desnoyers
@ 2023-05-05 18:08           ` Linus Torvalds
  2023-05-06  1:12           ` Huang, Ying
  1 sibling, 0 replies; 17+ messages in thread
From: Linus Torvalds @ 2023-05-05 18:08 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Huang, Ying, Andrew Morton, linux-kernel, Peter Zijlstra

On Fri, May 5, 2023 at 7:23 AM Mathieu Desnoyers
<mathieu.desnoyers@efficios.com> wrote:
>
> Is a list iteration position absolutely required to be a local variable,
> or can it be a dereferenced pointer ?

Well, it was certainly the intention, but while the member name
obviously has to be a member name, the iterator *could* be any lvalue.

Many of the "foreach" kind of loops would actually prefer to have
entirely local variables, but C syntax rules didn't allow that (now
with C11 we can do that variable declaration in the for-loop itself,
but we're still limited to just _one_ variable which can be a
problem).

So if we had started with C11, that 'list_for_each()' wouldn't have
had an external 'pos' declaration at all, it would have done it
internally, but that's not the reality we're in today ;/

              Linus

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC PATCH 4/4] llist.h: Fix parentheses around macro pointer parameter use
  2023-05-05 14:23         ` Mathieu Desnoyers
  2023-05-05 18:08           ` Linus Torvalds
@ 2023-05-06  1:12           ` Huang, Ying
  1 sibling, 0 replies; 17+ messages in thread
From: Huang, Ying @ 2023-05-06  1:12 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, Peter Zijlstra

Mathieu Desnoyers <mathieu.desnoyers@efficios.com> writes:

> On 2023-05-04 13:16, Linus Torvalds wrote:
>> On Thu, May 4, 2023 at 7:54/AM Mathieu Desnoyers
>> <mathieu.desnoyers@efficios.com> wrote:
>>> +#define list_prepare_entry(pos, head, member) \
>>> +       ((pos) ? : list_entry(head, typeof(*pos), member))
>>>
>>> So even though the fact that "pos" is used as an lvalue specifically in
>>> llist_for_each_entry_safe() makes it so that the parentheses are not
>>> strictly required around "pos" in typeof(*pos), I argue that we should
>>> still add those for consistency.
>> Ack. It may not matter in reality because of how 'pos' is supposed
>> to
>> be just a local variable name, but I agree that for consistency our
>> macros should still follow the usual pattern.
>> Of course, *because* of how 'pos' is not some random expression, and
>> is supposed to be that local variable, and because of how it is used,
>> it must always violate the whole "only use once" usual pattern,.
>> Exactly the same way the member name is also typically used multiple
>> times because of how it's not an expression, but really a "part of the
>> syntax".
>> So an alternative might be that we should use a different syntax for
>> those things and make it clear that they are not normal expressions.
>> Some people use upper-case names for special things like that to make
>> them stand out as "not normal" (kind of the same way upper-case macros
>> themselves were a warning that they weren't normal and might evaluate
>> arguments multiple times).
>
> Is a list iteration position absolutely required to be a local variable,
> or can it be a dereferenced pointer ?
>
> Let's say we take "list_for_each()" as example:
>
> #define list_for_each(pos, head) \
>         for (pos = (head)->next; !list_is_head(pos, head); pos = pos->next)
>
> and turn "pos" into "POS" to make it clearer that it is used as an lvalue:
>
> #define list_for_each(POS, head) \
>         for (POS = (head)->next; !list_is_head(POS, head); pos = POS->next)
>
> The following usage pattern is still broken:
>
> struct list_head list;
>
> void f(struct list_head **ppos)
> {
>   list_for_each(*ppos, &list) {
>     //...
>   }
> }
>
> Because ->next has higher operator precedence than "*", which is unexpected.
>
> I would argue that even if we choose to capitalize the macro special arguments used
> as lvalues and as member names so they stand out, it does not eliminate the need to
> be careful about proper use of parentheses around those parameters when they are also
> used as rvalues.

Yes.  The special parameter isn't necessary a variable name (except the
member name).  So special parameters

- are lvalue or member name
- may be "evaluated" multiple times

This makes them special enough from other macro parameters.  And we
still need to be careful about them (for example, when used as rvalue)
as other macro parameters.

Best Regards,
Huang, Ying

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-05-06  1:13 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-04  1:29 [RFC PATCH 1/4] rcu: rcupdate.h: Add missing parentheses around macro pointer dereference Mathieu Desnoyers
2023-05-04  1:29 ` [RFC PATCH 2/4] list.h: Fix parentheses around macro pointer parameter use Mathieu Desnoyers
2023-05-04 14:41   ` Andy Shevchenko
2023-05-04 14:45     ` Mathieu Desnoyers
2023-05-04  1:29 ` [RFC PATCH 3/4] rculist.h: " Mathieu Desnoyers
2023-05-04 16:19   ` Joel Fernandes
2023-05-05 14:06     ` Steven Rostedt
2023-05-05 14:35       ` Joel Fernandes
2023-05-05 15:02         ` Steven Rostedt
2023-05-04  1:29 ` [RFC PATCH 4/4] llist.h: " Mathieu Desnoyers
2023-05-04  5:54   ` Huang, Ying
2023-05-04 14:54     ` Mathieu Desnoyers
2023-05-04 17:16       ` Linus Torvalds
2023-05-05  1:38         ` Huang, Ying
2023-05-05 14:23         ` Mathieu Desnoyers
2023-05-05 18:08           ` Linus Torvalds
2023-05-06  1:12           ` Huang, Ying

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).