From: Benjamin Marzinski <bmarzins@redhat.com>
To: Martin Wilck <martin.wilck@suse.com>
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>,
dm-devel@lists.linux.dev, Martin Wilck <mwilck@suse.com>
Subject: Re: [PATCH 17/21] libmpathutil: use union for bitfield
Date: Thu, 18 Dec 2025 19:17:28 -0500 [thread overview]
Message-ID: <aUSZmCKh12TEqq86@redhat.com> (raw)
In-Reply-To: <20251217212113.234959-18-mwilck@suse.com>
On Wed, Dec 17, 2025 at 10:21:09PM +0100, Martin Wilck wrote:
> The macro BITFIELD used a cast of a pointer to a different anonymous struct
> to (struct bitfield *). This violates strict aliasing rules, because the
> two structs aren't compatible types in the sense of the language
> specification. With -O2, gcc 15.1 generates code that makes th pgcmp()
> function fail, because the compiler doesn't initialize bf->len aka
> __storage_for__bf.len to 64.
>
> The problem will show through error messages like this:
>
> multipathd[1974208]: is_bit_set_in_bitfield: bitfield overflow: 1 >= 0
>
> Fix this by using a union
>
> Fixes: 9a2f173 ("libmpathutil: change STATIC_BITFIELD to BITFIELD")
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
> libmpathutil/util.c | 8 ++++----
> libmpathutil/util.h | 41 +++++++++++++++++++++++----------------
> libmultipath/configure.c | 4 ++--
> libmultipath/pgpolicies.c | 2 +-
> tests/util.c | 10 +++++-----
> 5 files changed, 36 insertions(+), 29 deletions(-)
>
> diff --git a/libmpathutil/util.c b/libmpathutil/util.c
> index 37412c6..5e45750 100644
> --- a/libmpathutil/util.c
> +++ b/libmpathutil/util.c
> @@ -337,15 +337,15 @@ void cleanup_fclose(void *p)
> fclose(p);
> }
>
> -void cleanup_bitfield(struct bitfield **p)
> +void cleanup_bitfield(union bitfield **p)
> {
> free(*p);
> }
>
> -struct bitfield *alloc_bitfield(unsigned int maxbit)
> +union bitfield *alloc_bitfield(unsigned int maxbit)
> {
> unsigned int n;
> - struct bitfield *bf;
> + union bitfield *bf;
>
> if (maxbit == 0) {
> errno = EINVAL;
> @@ -353,7 +353,7 @@ struct bitfield *alloc_bitfield(unsigned int maxbit)
> }
>
> n = (maxbit - 1) / bits_per_slot + 1;
> - bf = calloc(1, sizeof(struct bitfield) + n * sizeof(bitfield_t));
> + bf = calloc(1, sizeof(union bitfield) + (n - 1) * sizeof(bitfield_t));
> if (bf)
> bf->len = maxbit;
> return bf;
> diff --git a/libmpathutil/util.h b/libmpathutil/util.h
> index 3799fd4..1ec6a46 100644
> --- a/libmpathutil/util.h
> +++ b/libmpathutil/util.h
> @@ -86,29 +86,36 @@ typedef unsigned int bitfield_t;
> #endif
> #define bits_per_slot (sizeof(bitfield_t) * CHAR_BIT)
>
> -struct bitfield {
> - unsigned int len;
> - bitfield_t bits[];
> +union bitfield {
> + struct {
> + unsigned int len;
> + bitfield_t bits[];
> + };
> + /* for initialization in the BITFIELD macro */
> + struct {
> + unsigned int __len;
> + bitfield_t __bits[1];
> + };
> };
>
> -#define BITFIELD(name, length) \
> - struct { \
> - unsigned int len; \
> - bitfield_t bits[((length) - 1) / bits_per_slot + 1]; \
> - } __storage_for__ ## name = { \
> - .len = (length), \
> - .bits = { 0, }, \
> +/*
> + * gcc 4.9.2 (Debian Jessie) raises an error if the initializer for
> + * .__len comes first. Thus put .__bits first.
> + */
> +#define BITFIELD(name, length) \
> + union bitfield __storage_for__ ## name = { \
> + .__bits = { 0 }, \
> + .__len = (length), \
> }; \
It looks like this only allocates one bitfield_t, regardless of length.
Am I missing something here?
-Ben
> - struct bitfield *name = (struct bitfield *)& __storage_for__ ## name
> + union bitfield *name = & __storage_for__ ## name
>
> -struct bitfield *alloc_bitfield(unsigned int maxbit);
> +union bitfield *alloc_bitfield(unsigned int maxbit);
>
> void log_bitfield_overflow__(const char *f, unsigned int bit, unsigned int len);
> #define log_bitfield_overflow(bit, len) \
> log_bitfield_overflow__(__func__, bit, len)
>
> -static inline bool is_bit_set_in_bitfield(unsigned int bit,
> - const struct bitfield *bf)
> +static inline bool is_bit_set_in_bitfield(unsigned int bit, const union bitfield *bf)
> {
> if (bit >= bf->len) {
> log_bitfield_overflow(bit, bf->len);
> @@ -118,7 +125,7 @@ static inline bool is_bit_set_in_bitfield(unsigned int bit,
> (1ULL << (bit % bits_per_slot)));
> }
>
> -static inline void set_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> +static inline void set_bit_in_bitfield(unsigned int bit, union bitfield *bf)
> {
> if (bit >= bf->len) {
> log_bitfield_overflow(bit, bf->len);
> @@ -127,7 +134,7 @@ static inline void set_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> bf->bits[bit / bits_per_slot] |= (1ULL << (bit % bits_per_slot));
> }
>
> -static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> +static inline void clear_bit_in_bitfield(unsigned int bit, union bitfield *bf)
> {
> if (bit >= bf->len) {
> log_bitfield_overflow(bit, bf->len);
> @@ -146,5 +153,5 @@ static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
> void cleanup_charp(char **p);
> void cleanup_ucharp(unsigned char **p);
> void cleanup_udev_device(struct udev_device **udd);
> -void cleanup_bitfield(struct bitfield **p);
> +void cleanup_bitfield(union bitfield **p);
> #endif /* UTIL_H_INCLUDED */
> diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> index a8e18a2..41b6a9f 100644
> --- a/libmultipath/configure.c
> +++ b/libmultipath/configure.c
> @@ -440,7 +440,7 @@ static int pgcmp(struct multipath *mpp, struct multipath *cmpp)
> int i, j;
> struct pathgroup *pgp, *cpgp;
> BITFIELD(bf, bits_per_slot);
> - struct bitfield *bf__ __attribute__((cleanup(cleanup_bitfield))) = NULL;
> + union bitfield *bf__ __attribute__((cleanup(cleanup_bitfield))) = NULL;
>
> if (VECTOR_SIZE(mpp->pg) != VECTOR_SIZE(cmpp->pg))
> return 1;
> @@ -1049,7 +1049,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
> vector newmp;
> struct config *conf = NULL;
> int allow_queueing;
> - struct bitfield *size_mismatch_seen;
> + union bitfield *size_mismatch_seen;
> struct multipath * cmpp;
>
> /* ignore refwwid if it's empty */
> diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
> index 2e1a543..57b7485 100644
> --- a/libmultipath/pgpolicies.c
> +++ b/libmultipath/pgpolicies.c
> @@ -201,7 +201,7 @@ int group_by_match(struct multipath * mp, vector paths,
> bool (*path_match_fn)(struct path *, struct path *))
> {
> int i, j;
> - struct bitfield *bitmap;
> + union bitfield *bitmap;
> struct path * pp;
> struct pathgroup * pgp;
> struct path * pp2;
> diff --git a/tests/util.c b/tests/util.c
> index da192ba..67d8148 100644
> --- a/tests/util.c
> +++ b/tests/util.c
> @@ -198,7 +198,7 @@ static uint64_t maybe_swap(uint64_t v)
>
> static void test_bitmask_1(void **state)
> {
> - struct bitfield *bf;
> + union bitfield *bf;
> uint64_t *arr;
> int i, j, k, m, b;
>
> @@ -240,7 +240,7 @@ static void test_bitmask_1(void **state)
>
> static void test_bitmask_2(void **state)
> {
> - struct bitfield *bf;
> + union bitfield *bf;
> uint64_t *arr;
> int i, j, k, m, b;
>
> @@ -307,7 +307,7 @@ static void test_bitmask_2(void **state)
> */
> static void test_bitmask_len_0(void **state)
> {
> - struct bitfield *bf;
> + union bitfield *bf;
>
> bf = alloc_bitfield(0);
> assert_null(bf);
> @@ -329,7 +329,7 @@ static unsigned int maybe_swap_idx(unsigned int i)
>
> static void _test_bitmask_small(unsigned int n)
> {
> - struct bitfield *bf;
> + union bitfield *bf;
> uint32_t *arr;
> unsigned int size = maybe_swap_idx((n - 1) / 32) + 1, i;
>
> @@ -378,7 +378,7 @@ static void _test_bitmask_small(unsigned int n)
>
> static void _test_bitmask_small_2(unsigned int n)
> {
> - struct bitfield *bf;
> + union bitfield *bf;
> uint32_t *arr;
> unsigned int size = maybe_swap_idx((n - 1) / 32) + 1, i;
>
> --
> 2.52.0
next prev parent reply other threads:[~2025-12-19 0:17 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-17 21:20 [PATCH 00/21] Multipath-tools: various bug fixes Martin Wilck
2025-12-17 21:20 ` [PATCH 01/21] libmultipath: drop drop_multipath Martin Wilck
2025-12-17 21:20 ` [PATCH 02/21] libmultipath: don't access path members in free_pgvec() Martin Wilck
2025-12-17 21:20 ` [PATCH 03/21] multipathd: free paths in checker_finished() Martin Wilck
2025-12-18 23:34 ` Benjamin Marzinski
2025-12-18 23:40 ` Martin Wilck
2025-12-19 10:38 ` Martin Wilck
2025-12-17 21:20 ` [PATCH 04/21] libmultipath: don't touch mpvec in remove_map() Martin Wilck
2025-12-17 21:20 ` [PATCH 05/21] libmpathutil: constify find_slot() Martin Wilck
2025-12-17 21:20 ` [PATCH 06/21] libmultipath: don't free paths in orphan_paths() Martin Wilck
2025-12-17 21:20 ` [PATCH 07/21] libmultipath: free orphaned paths in check_removed_paths() Martin Wilck
2025-12-17 21:21 ` [PATCH 08/21] libmultipath: remove free_paths argument from free_pathgroup() Martin Wilck
2025-12-17 21:21 ` [PATCH 09/21] libmultipath: fix numeric value of free_paths in free_multipaths() Martin Wilck
2025-12-19 0:10 ` Benjamin Marzinski
2025-12-17 21:21 ` [PATCH 10/21] libmultipath: remove free_paths argument from free_pgvec() Martin Wilck
2025-12-17 21:21 ` [PATCH 11/21] libmultipath: remove free_paths argument from free_multipathvec() Martin Wilck
2025-12-17 21:21 ` [PATCH 12/21] libmultipath: free_multipath: fix FREE_PATHS case Martin Wilck
2025-12-19 0:15 ` Benjamin Marzinski
2025-12-17 21:21 ` [PATCH 13/21] multipath-tools: Fix ISO C23 errors with strchr() Martin Wilck
2025-12-17 21:21 ` [PATCH 14/21] libmultipath: simplify sysfs_get_target_nodename() Martin Wilck
2025-12-17 21:21 ` [PATCH 15/21] multipathd: join the init_unwinder dummy thread Martin Wilck
2025-12-17 21:21 ` [PATCH 16/21] kpartx: fix some memory leaks Martin Wilck
2025-12-17 21:21 ` [PATCH 17/21] libmpathutil: use union for bitfield Martin Wilck
2025-12-19 0:17 ` Benjamin Marzinski [this message]
2025-12-19 8:08 ` Martin Wilck
2025-12-17 21:21 ` [PATCH 18/21] libmpathutil: add wrapper code for libudev Martin Wilck
2025-12-19 0:38 ` Benjamin Marzinski
2025-12-19 8:06 ` Martin Wilck
2025-12-19 17:27 ` Benjamin Marzinski
2025-12-17 21:21 ` [PATCH 19/21] multipath-tools: use the libudev wrapper functions Martin Wilck
2025-12-17 21:21 ` [PATCH 20/21] Makefile: add functionality to determine cmocka version Martin Wilck
2025-12-17 21:21 ` [PATCH 21/21] multipath-tools tests: adaptations for cmocka 2.0 Martin Wilck
2025-12-19 0:40 ` [PATCH 00/21] Multipath-tools: various bug fixes Benjamin Marzinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aUSZmCKh12TEqq86@redhat.com \
--to=bmarzins@redhat.com \
--cc=christophe.varoqui@opensvc.com \
--cc=dm-devel@lists.linux.dev \
--cc=martin.wilck@suse.com \
--cc=mwilck@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox