(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