[v2,08/10] hash: fix unaligned access in predictable RSS
Checks
Commit Message
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
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
>
> 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
>
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).
> 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
>
@@ -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));