(Commit message below adapted from libnbd commit fda38988b86b, "vector:
introduce DEFINE_POINTER_VECTOR_TYPE()", 2023-02-28).

The "name##_iter" function is used 5 times in nbdkit as follows:

  string_vector_iter (..., (void *) free);

Casting "free" to (void*) is ugly. (Well-defined by POSIX, but still.)

Furthermore, in those 5 cases, the freeing of the vector's strings is
immediately followed by the release of the vector's array-of-pointers too.
(This additional step is not expressed consistently across nbdkit: it's
sometimes spelled as free(vec.ptr), sometimes as
string_vector_reset(&vec).)

Introduce "name##_empty", which performs both steps at the same time.

Expose the "name##_empty" function definition with a new, separate macro:
ADD_VECTOR_EMPTY_METHOD(). The existent DEFINE_VECTOR_TYPE() macro permits
such element types that are not pointers, or are pointers to const- and/or
volatile-qualified objects. Whereas "name##_empty" requires that the
elements be pointers to dynamically allocated, non-const, non-volatile
objects.

Add DEFINE_POINTER_VECTOR_TYPE() that expands to both DEFINE_VECTOR_TYPE()
and the additive ADD_VECTOR_EMPTY_METHOD().

(

For example, after

  typedef char foobar[5];

the following compiles (as expected):

  DEFINE_VECTOR_TYPE (foobar_vector, foobar);

and the following fails to build (as expected):

  DEFINE_POINTER_VECTOR_TYPE (foobar_vector_bad, foobar);

with the diagnostics including

> In function ‘foobar_vector_bad_empty’:
> error: size of array ‘_vector_contains_pointers1’ is negative

)

Switch "string_vector" to DEFINE_POINTER_VECTOR_TYPE(). The 5
string_vector_iter() call sites continue working; they will be converted
to string_vector_empty() in a subsequent patch.

Signed-off-by: Laszlo Ersek <ler...@redhat.com>
(cherry picked from libnbd commit fda38988b86bb133b56fc6251b2d581e809b3b67)
---
 Makefile.am                  |  1 +
 common/utils/string-vector.h |  2 +-
 common/utils/vector.h        | 35 ++++++++++++++++++++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index caa206064008..9bd942538d0d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,6 +58,7 @@ noinst_PROGRAMS = nbdkit
 nbdkit_SOURCES = wrapper.c server/options.h
 nbdkit_CPPFLAGS = \
        -I$(top_srcdir)/server \
+       -I$(top_srcdir)/common/include \
        -I$(top_srcdir)/common/utils \
        -I$(top_srcdir)/common/replacements \
        -Dbuilddir=\"$(abs_top_builddir)\" \
diff --git a/common/utils/string-vector.h b/common/utils/string-vector.h
index 7309ca4aa13d..40446008b6a9 100644
--- a/common/utils/string-vector.h
+++ b/common/utils/string-vector.h
@@ -37,7 +37,7 @@
 
 #include "vector.h"
 
-DEFINE_VECTOR_TYPE (string_vector, char *);
+DEFINE_POINTER_VECTOR_TYPE (string_vector, char *);
 
 /* This frees both the array and the strings. */
 #define CLEANUP_FREE_STRING_VECTOR \
diff --git a/common/utils/vector.h b/common/utils/vector.h
index 5f5f96e97ab2..9549fa9e6f2f 100644
--- a/common/utils/vector.h
+++ b/common/utils/vector.h
@@ -44,6 +44,9 @@
 #include <assert.h>
 #include <string.h>
 
+#include "compiler-macros.h"
+#include "static-assert.h"
+
 #ifdef __clang__
 #pragma clang diagnostic ignored "-Wunused-function"
 #pragma clang diagnostic ignored "-Wduplicate-decl-specifier"
@@ -200,6 +203,38 @@
 
 #define empty_vector { .ptr = NULL, .len = 0, .cap = 0 }
 
+/* This macro should only be used if:
+ * - the vector contains pointers, and
+ * - the pointed-to objects are:
+ *   - neither const- nor volatile-qualified, and
+ *   - allocated with malloc() or equivalent.
+ */
+#define ADD_VECTOR_EMPTY_METHOD(name)                                  \
+  /* Call free() on each element of the vector, then reset the vector. \
+   */                                                                  \
+  static inline void __attribute__ ((__unused__))                      \
+  name##_empty (name *v)                                               \
+  {                                                                    \
+    size_t i;                                                          \
+    for (i = 0; i < v->len; ++i) {                                     \
+      STATIC_ASSERT (TYPE_IS_POINTER (v->ptr[i]),                      \
+                     _vector_contains_pointers);                       \
+      free (v->ptr[i]);                                                \
+    }                                                                  \
+    name##_reset (v);                                                  \
+  }                                                                    \
+                                                                       \
+  /* Force callers to supply ';'. */                                   \
+  struct name
+
+/* Convenience macro tying together DEFINE_VECTOR_TYPE() and
+ * ADD_VECTOR_EMPTY_METHOD(). Inherit and forward the requirement for a
+ * trailing semicolon from ADD_VECTOR_EMPTY_METHOD() to the caller.
+ */
+#define DEFINE_POINTER_VECTOR_TYPE(name, type) \
+  DEFINE_VECTOR_TYPE (name, type);             \
+  ADD_VECTOR_EMPTY_METHOD (name)
+
 struct generic_vector {
   void *ptr;
   size_t len;

_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to