diff mbox series

[ovs-dev,v4,01/15] util: add multi-variable loop iterator macros

Message ID 20220309161023.3347758-2-amorenoz@redhat.com
State Superseded
Headers show
Series Fix undefined behavior in loop macros | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test fail github build: failed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Adrián Moreno March 9, 2022, 4:10 p.m. UTC
Multi-variable loop iterators avoid potential undefined behavior by
using an internal iterator variable to perform the iteration and only
referencing the containing object (via OBJECT_CONTAINING) if the
iterator has been validated via the second expression of the for
statement.

That way, the user can easily implement a loop that never tries to
obtain the object containing NULL or stack-allocated non-contained
nodes.

When the loop ends normally (not via "break;") the user-provided
variable is set to NULL.

Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
---
 include/openvswitch/util.h | 43 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

Comments

Eelco Chaudron March 18, 2022, 1:14 p.m. UTC | #1
On 9 Mar 2022, at 17:10, Adrian Moreno wrote:

> Multi-variable loop iterators avoid potential undefined behavior by
> using an internal iterator variable to perform the iteration and only
> referencing the containing object (via OBJECT_CONTAINING) if the
> iterator has been validated via the second expression of the for
> statement.
>
> That way, the user can easily implement a loop that never tries to
> obtain the object containing NULL or stack-allocated non-contained
> nodes.
>
> When the loop ends normally (not via "break;") the user-provided
> variable is set to NULL.
>
> Signed-off-by: Adrian Moreno <amorenoz@redhat.com>

Not sure if this is the patchset to start reviewing on a Friday, but I promised!

Went over the first couple of patches (more than once; I hate MACRO’s), and other than some small nits they look fine. I will continue the review later...

Acked-by: Eelco Chaudron <echaudro@redhat.com>
diff mbox series

Patch

diff --git a/include/openvswitch/util.h b/include/openvswitch/util.h
index 228b185c3..2d81e3574 100644
--- a/include/openvswitch/util.h
+++ b/include/openvswitch/util.h
@@ -145,6 +145,49 @@  OVS_NO_RETURN void ovs_assert_failure(const char *, const char *, const char *);
 #define INIT_CONTAINER(OBJECT, POINTER, MEMBER) \
     ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER))
 
+/* Multi-variable container iterators.
+ *
+ * The following macros facilitate safe iteration over data structures
+ * contained in objects. It does so by using an internal iterator variable of
+ * the type of the member object pointer (i.e: pointer to the data structure).
+ */
+
+/* Multi-variable iterator variable name.
+ * Returns the name of the internal iterator variable.
+ */
+#define ITER_VAR(NAME) NAME ## __iterator__
+
+/* Multi-variable initialization. Creates an internal iterator variable that
+ * points to the provided pointer. The type of the iterator variable is
+ * ITER_TYPE*. It must be the same type as &VAR->MEMBER.
+ *
+ * The _EXP version evaluates the extra expressions once.
+ */
+#define INIT_MULTIVAR(VAR, MEMBER, POINTER, ITER_TYPE)                  \
+    INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, ITER_TYPE, (void) 0)
+
+#define INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, ITER_TYPE, ...)         \
+    ITER_TYPE *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER)
+
+/* Multi-variable condition.
+ * Evaluates the condition expression (that must be based on the internal
+ * iterator variable). Only if the result of expression is true, the OBJECT is
+ * set to the object containing the current value of the iterator variable.
+ *
+ * It is up to the caller to make sure it is safe to run OBJECT_CONTAINING on
+ * the pointers that verify the condition.
+ */
+#define CONDITION_MULTIVAR(VAR, MEMBER, EXPR)                                 \
+    ((EXPR) ?                                                                 \
+     (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)), 1) :           \
+     (((VAR) = NULL), 0))
+
+/* Multi-variable update.
+ * Sets the iterator value to NEXT_ITER.
+ */
+#define UPDATE_MULTIVAR(VAR, NEXT_ITER)                                       \
+    (ITER_VAR(VAR) = NEXT_ITER)
+
 /* Returns the number of elements in ARRAY. */
 #define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY)