All of lore.kernel.org
 help / color / mirror / Atom feed
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


  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.