[v2,08/10] hash: fix unaligned access in predictable RSS

Message ID 20250623135242.461965-9-david.marchand@redhat.com (mailing list archive)
State Superseded
Delegated to: Thomas Monjalon
Headers
Series Run with UBSan in GHA |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

David Marchand June 23, 2025, 1:52 p.m. UTC
Caught by UBSan:

../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
	0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
	which requires 4 byte alignment

Fixes: 28ebff11c2dc ("hash: add predictable RSS")
Cc: stable@dpdk.org

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 lib/hash/rte_thash.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
  

Comments

Bruce Richardson June 30, 2025, 3:32 p.m. UTC | #1
On Mon, Jun 23, 2025 at 03:52:38PM +0200, David Marchand wrote:
> Caught by UBSan:
> 
> ../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
> 	0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
> 	which requires 4 byte alignment
> 
> Fixes: 28ebff11c2dc ("hash: add predictable RSS")
> Cc: stable@dpdk.org
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> ---
>  lib/hash/rte_thash.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
> index 6c662bf14f..6d4dbea6d7 100644
> --- a/lib/hash/rte_thash.c
> +++ b/lib/hash/rte_thash.c
> @@ -415,10 +415,10 @@ generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
>  static inline uint32_t
>  get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
>  {
> -	uint32_t *tmp, val;
> +	uint32_t tmp, val;
>  
> -	tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
> -	val = rte_be_to_cpu_32(*tmp);
> +	memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
> +	val = rte_be_to_cpu_32(tmp);
>  	val >>= (TOEPLITZ_HASH_LEN - ((offset & (CHAR_BIT - 1)) +
>  		ctx->reta_sz_log));
>  
> -- 
> 2.49.0
>
  
Konstantin Ananyev July 1, 2025, 8:36 a.m. UTC | #2
> Caught by UBSan:
> 
> ../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
> 	0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
> 	which requires 4 byte alignment
> 
> Fixes: 28ebff11c2dc ("hash: add predictable RSS")
> Cc: stable@dpdk.org
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
>  lib/hash/rte_thash.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
> index 6c662bf14f..6d4dbea6d7 100644
> --- a/lib/hash/rte_thash.c
> +++ b/lib/hash/rte_thash.c
> @@ -415,10 +415,10 @@ generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
>  static inline uint32_t
>  get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
>  {
> -	uint32_t *tmp, val;
> +	uint32_t tmp, val;
> 
> -	tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
> -	val = rte_be_to_cpu_32(*tmp);
> +	memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
> +	val = rte_be_to_cpu_32(tmp);

Just wonder do you guys consider it as a real one?
AFAIK, all architectures that we care about do support unaligned load for 32-bit integers.

>  	val >>= (TOEPLITZ_HASH_LEN - ((offset & (CHAR_BIT - 1)) +
>  		ctx->reta_sz_log));
> 
> --
> 2.49.0
>
  
David Marchand July 8, 2025, 7:32 a.m. UTC | #3
On Tue, Jul 1, 2025 at 10:36 AM Konstantin Ananyev
<konstantin.ananyev@huawei.com> wrote:
> > Caught by UBSan:
> >
> > ../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
> >       0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
> >       which requires 4 byte alignment
> >
> > Fixes: 28ebff11c2dc ("hash: add predictable RSS")
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> >  lib/hash/rte_thash.c | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
> > index 6c662bf14f..6d4dbea6d7 100644
> > --- a/lib/hash/rte_thash.c
> > +++ b/lib/hash/rte_thash.c
> > @@ -415,10 +415,10 @@ generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
> >  static inline uint32_t
> >  get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
> >  {
> > -     uint32_t *tmp, val;
> > +     uint32_t tmp, val;
> >
> > -     tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
> > -     val = rte_be_to_cpu_32(*tmp);
> > +     memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
> > +     val = rte_be_to_cpu_32(tmp);
>
> Just wonder do you guys consider it as a real one?
> AFAIK, all architectures that we care about do support unaligned load for 32-bit integers.

Well this is undefined behavior, regardless of what the architecture support.
And the compiler may end up generating wrong code.

I could revisit this change with the aliasing trick (used for rte_memcpy).
  
Konstantin Ananyev July 8, 2025, 5:58 p.m. UTC | #4
> On Tue, Jul 1, 2025 at 10:36 AM Konstantin Ananyev
> <konstantin.ananyev@huawei.com> wrote:
> > > Caught by UBSan:
> > >
> > > ../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
> > >       0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
> > >       which requires 4 byte alignment
> > >
> > > Fixes: 28ebff11c2dc ("hash: add predictable RSS")
> > > Cc: stable@dpdk.org
> > >
> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > ---
> > >  lib/hash/rte_thash.c | 6 +++---
> > >  1 file changed, 3 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
> > > index 6c662bf14f..6d4dbea6d7 100644
> > > --- a/lib/hash/rte_thash.c
> > > +++ b/lib/hash/rte_thash.c
> > > @@ -415,10 +415,10 @@ generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
> > >  static inline uint32_t
> > >  get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
> > >  {
> > > -     uint32_t *tmp, val;
> > > +     uint32_t tmp, val;
> > >
> > > -     tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
> > > -     val = rte_be_to_cpu_32(*tmp);
> > > +     memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
> > > +     val = rte_be_to_cpu_32(tmp);
> >
> > Just wonder do you guys consider it as a real one?
> > AFAIK, all architectures that we care about do support unaligned load for 32-bit integers.
> 
> Well this is undefined behavior, regardless of what the architecture support.
> And the compiler may end up generating wrong code.

Probably, though AFAIK, we do have a lot of code that load 32-bit values from possibly
non-aligned addresses (nearly all packet parsing does that).
I wonder why it only complained only about that one? 
BTW, would our 'unaligned_uint32_t' type help here?

> I could revisit this change with the aliasing trick (used for rte_memcpy).
> 
> 
> --
> David Marchand
>
  
David Marchand July 15, 2025, 11:57 a.m. UTC | #5
On Tue, Jul 8, 2025 at 7:58 PM Konstantin Ananyev
<konstantin.ananyev@huawei.com> wrote:
> > > Just wonder do you guys consider it as a real one?
> > > AFAIK, all architectures that we care about do support unaligned load for 32-bit integers.
> >
> > Well this is undefined behavior, regardless of what the architecture support.
> > And the compiler may end up generating wrong code.
>
> Probably, though AFAIK, we do have a lot of code that load 32-bit values from possibly
> non-aligned addresses (nearly all packet parsing does that).
> I wonder why it only complained only about that one?

Probably because unit tests coverage is (too) small.


> BTW, would our 'unaligned_uint32_t' type help here?

Since most DPDK code rely on aligned types, using an unaligned type
can work if we have a function that serves as a conversion from
unaligned to aligned types.
In this code, since the next operation is a byte swap operation on
32bits, I don't think we have many option but to memcpy().
  
Konstantin Ananyev July 15, 2025, 1:32 p.m. UTC | #6
> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Tuesday, July 15, 2025 12:57 PM
> To: Konstantin Ananyev <konstantin.ananyev@huawei.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Yipeng Wang <yipeng1.wang@intel.com>; Sameh Gobriel <sameh.gobriel@intel.com>; Bruce
> Richardson <bruce.richardson@intel.com>; Vladimir Medvedkin <vladimir.medvedkin@intel.com>; John McNamara
> <john.mcnamara@intel.com>
> Subject: Re: [PATCH v2 08/10] hash: fix unaligned access in predictable RSS
> 
> On Tue, Jul 8, 2025 at 7:58 PM Konstantin Ananyev
> <konstantin.ananyev@huawei.com> wrote:
> > > > Just wonder do you guys consider it as a real one?
> > > > AFAIK, all architectures that we care about do support unaligned load for 32-bit integers.
> > >
> > > Well this is undefined behavior, regardless of what the architecture support.
> > > And the compiler may end up generating wrong code.
> >
> > Probably, though AFAIK, we do have a lot of code that load 32-bit values from possibly
> > non-aligned addresses (nearly all packet parsing does that).
> > I wonder why it only complained only about that one?
> 
> Probably because unit tests coverage is (too) small.
> 
> 
> > BTW, would our 'unaligned_uint32_t' type help here?
> 
> Since most DPDK code rely on aligned types, using an unaligned type
> can work if we have a function that serves as a conversion from
> unaligned to aligned types.
> In this code, since the next operation is a byte swap operation on
> 32bits, I don't think we have many option but to memcpy().

[] For clarity, I am talking about something like that:
https://godbolt.org/z/vv6qzPMTz
  
David Marchand July 15, 2025, 2:54 p.m. UTC | #7
On Tue, Jul 15, 2025 at 3:33 PM Konstantin Ananyev
<konstantin.ananyev@huawei.com> wrote:
> > > BTW, would our 'unaligned_uint32_t' type help here?
> >
> > Since most DPDK code rely on aligned types, using an unaligned type
> > can work if we have a function that serves as a conversion from
> > unaligned to aligned types.
> > In this code, since the next operation is a byte swap operation on
> > 32bits, I don't think we have many option but to memcpy().
>
> [] For clarity, I am talking about something like that:
> https://godbolt.org/z/vv6qzPMTz

I did not think just the cast would be enough, but it seems to work,
ok I'll respin.
  
Mattias Rönnblom July 16, 2025, 6 a.m. UTC | #8
On 2025-06-23 15:52, David Marchand wrote:
> Caught by UBSan:
> 
> ../lib/hash/rte_thash.c:421:8: runtime error: load of misaligned address
> 	0x0001816c2da3 for type 'uint32_t' (aka 'unsigned int'),
> 	which requires 4 byte alignment
> 
> Fixes: 28ebff11c2dc ("hash: add predictable RSS")
> Cc: stable@dpdk.org
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>

Acked-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>

> ---
>   lib/hash/rte_thash.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
> index 6c662bf14f..6d4dbea6d7 100644
> --- a/lib/hash/rte_thash.c
> +++ b/lib/hash/rte_thash.c
> @@ -415,10 +415,10 @@ generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
>   static inline uint32_t
>   get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
>   {
> -	uint32_t *tmp, val;
> +	uint32_t tmp, val;
>   
> -	tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
> -	val = rte_be_to_cpu_32(*tmp);
> +	memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
> +	val = rte_be_to_cpu_32(tmp);
>   	val >>= (TOEPLITZ_HASH_LEN - ((offset & (CHAR_BIT - 1)) +
>   		ctx->reta_sz_log));
>
  

Patch

diff --git a/lib/hash/rte_thash.c b/lib/hash/rte_thash.c
index 6c662bf14f..6d4dbea6d7 100644
--- a/lib/hash/rte_thash.c
+++ b/lib/hash/rte_thash.c
@@ -415,10 +415,10 @@  generate_subkey(struct rte_thash_ctx *ctx, struct thash_lfsr *lfsr,
 static inline uint32_t
 get_subvalue(struct rte_thash_ctx *ctx, uint32_t offset)
 {
-	uint32_t *tmp, val;
+	uint32_t tmp, val;
 
-	tmp = (uint32_t *)(&ctx->hash_key[offset >> 3]);
-	val = rte_be_to_cpu_32(*tmp);
+	memcpy(&tmp, &ctx->hash_key[offset >> 3], sizeof(tmp));
+	val = rte_be_to_cpu_32(tmp);
 	val >>= (TOEPLITZ_HASH_LEN - ((offset & (CHAR_BIT - 1)) +
 		ctx->reta_sz_log));