|WARNING| [v2,5/5] arm: remove no longer used RTE_ARCH_STRICT_ALIGN
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Sun Sep 6 19:41:53 CEST 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/169121
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-09-06
# Review of DPDK Patch Series
## Patch 1/5: test: fix jhash 32 bit key type
### Errors
None found.
### Warnings
None found.
### Info
- The patch correctly changes `key` from `uint8_t[64]` to `uint32_t[16]` to match the expected input type for `rte_jhash_32b()`, which takes `const uint32_t*`.
- Uses `rte_rand()` instead of `rand()`, which is appropriate for DPDK code.
- The cast to `uint32_t` is safe since `rte_rand()` returns `uint64_t`.
- The division by `sizeof(uint32_t)` is clearer than the original `>> 2` shift.
---
## Patch 2/5: eal: RTE_PTR_ADD/SUB API improvements
### Errors
**1. NULL pointer handling inconsistency**
Multiple call sites add NULL checks before using `RTE_PTR_ADD`, but the macros themselves do not check for NULL. The documentation states "must be non-NULL" but does not enforce it. If NULL is undefined behavior, callers should not need to check; if they must check, the requirement is not clear.
```c
/* drivers/bus/cdx/cdx_vfio.c */
if (msl->base_va == NULL)
return 0;
end_va = RTE_PTR_ADD(msl->base_va, sz);
/* drivers/net/ena/ena_ethdev.c */
if (res->addr == NULL) {
PMD_INIT_LOG_LINE(DEBUG, "PCI BAR [%u] address is NULL", bar);
return NULL;
}
vaddr = RTE_PTR_ADD(res->addr, offset);
```
This pattern appears in:
- `drivers/bus/cdx/cdx_vfio.c`
- `drivers/bus/pci/linux/pci.c`
- `drivers/bus/vmbus/linux/vmbus_uio.c`
- `drivers/net/ena/ena_ethdev.c`
- `lib/eal/common/eal_common_memory.c` (multiple instances)
- `lib/eal/common/eal_common_fbarray.c`
- `lib/eal/freebsd/eal_memory.c`
- `lib/eal/linux/eal_memalloc.c`
- `lib/eal/linux/eal_memory.c`
- `lib/eal/windows/eal_memalloc.c`
- `lib/vhost/vhost_user.c`
**Issue**: If `RTE_PTR_ADD(NULL, x)` is undefined behavior (as the doc states), these checks are correct. However, the fact that so many call sites add NULL checks suggests callers cannot rely on the precondition being met. The API should either:
- Document that callers MUST ensure non-NULL (current doc), OR
- Make the macro tolerate NULL (return NULL when input is NULL).
The current approach is inconsistent: the doc says "must be non-NULL" but most call sites defensively check for NULL before calling. This indicates the precondition is not reliably met in practice.
**Recommendation**: Either remove the NULL checks (if the precondition is always met) or document that callers must validate inputs. The current mix of sometimes-checking, sometimes-not is a maintenance hazard.
**2. Missing NULL checks in assertion-protected code**
```c
/* lib/eal/common/malloc_elem.h */
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
if (data == NULL)
return NULL;
/* ... */
struct malloc_elem *elem =
RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
```
The function checks `data == NULL` and returns early, so `RTE_PTR_SUB` is never called with NULL. This is correct.
**3. Type preservation in test code**
```c
/* app/test-pmd/cmdline_flow.c */
*(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
```
The cast to `int *` is necessary because `RTE_PTR_ADD` returns `void *`. However, `action->conf` is `const void *`, and writing to a `const`-qualified object via a cast is undefined behavior if the original object was `const`. The `RTE_PTR_UNQUAL` removes the qualifier, but this may be hiding a correctness issue.
**Issue**: If `action->conf` points to a truly const object, this write is UB. The code should ensure `action->conf` is mutable before writing. This is a pre-existing issue, not introduced by this patch, but the new macro makes it more visible.
**4. Integer-to-pointer conversions**
Several driver changes replace `PLT_PTR_ADD(base, offset)` with manual pointer arithmetic on `uintptr_t`:
```c
/* drivers/common/cnxk/roc_ml.c */
-PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET)
+PLT_PTR_ADD_U64_CAST(
+ (void *)(uintptr_t)(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET)
```
The original `phys_addr` is `rte_iova_t` (a 64-bit integer, not a pointer). Converting it to `(void *)` via `(uintptr_t)` is correct for MMIO address computation, but the outer `PLT_PTR_ADD_U64_CAST` suggests this should be a simple addition, not pointer arithmetic. The code appears correct but convoluted.
**5. Pointer arithmetic on MMIO addresses**
```c
/* drivers/common/cnxk/roc_nix_bpf.c */
-addr = PLT_PTR_ADD(nix->base, off);
+addr = (void *)(uintptr_t)(nix->base + off);
```
`nix->base` is `uintptr_t` (MMIO base address). The original `PLT_PTR_ADD` treated it as a pointer; the new code treats it as an integer and casts to pointer. This is correct for MMIO, where the "pointer" is really an integer offset into device memory. However, `RTE_PTR_ADD` is documented for pointers, not integers. The manual cast is the right approach here.
**6. Volatile qualifier stripping**
```c
/* drivers/dma/idxd/idxd_pci.c */
-static uint32_t *
+static volatile uint32_t *
idxd_get_wq_cfg(struct idxd_pci_common *pci, uint8_t wq_idx)
{
return RTE_PTR_ADD(pci->wq_regs_base, ...);
}
```
The return type changed from `uint32_t *` to `volatile uint32_t *`. This is correct if `wq_regs_base` is MMIO (it should be volatile). The original code was wrong; this patch fixes it by preserving the qualifier.
**7. Const qualifier stripping in test code**
```c
/* drivers/dma/odm/odm_dmadev.c */
-const uint32_t *base_addr = vq->cring_mz->addr;
+uint32_t *base_addr = vq->cring_mz->addr;
```
The `const` was removed. If `cring_mz->addr` is mutable memory, this is correct. If it should be const, this is wrong. Need to verify `cring_mz->addr` is not const-qualified at the source.
Looking at the context: `cring_mz` is a memzone, and `addr` is mutable memory allocated from hugepages. The original `const` was incorrect (prevented writing completion status). Removing it is correct.
**8. Missing const in driver code**
```c
/* drivers/common/cnxk/roc_cpt_debug.c */
-struct cpt_frag_info_s *frag_info;
+const struct cpt_frag_info_s *frag_info;
```
The function `cpt_cnxk_parse_hdr_dump` takes `const struct cpt_parse_hdr_s *cpth` and derives `frag_info` from it via pointer arithmetic. The original code stripped const; the new code preserves it. This is correct.
### Warnings
**1. Extensive test changes without justification**
The test file `app/test/test_common.c` grew from ~350 lines to ~850 lines. The new tests are thorough, but:
- No explanation in the commit message for why this level of testing is needed.
- The tests duplicate coverage already provided by real usage (the driver changes).
- Some edge case tests (address space boundaries) are theoretical and unlikely to catch real bugs.
**Recommendation**: The core functionality tests (type preservation, alignment) are valuable. The boundary tests could be simplified or moved to a separate "stress test" suite.
**2. Release notes claim "not nesting infinitely"**
```
These macros do not nest infinitely and may require intermediate variables.
```
This is vague. What breaks when nesting? Provide an example of correct vs. incorrect usage.
**3. Deprecation of integer arguments**
```
RTE_PTR_ADD and RTE_PTR_SUB no longer accept integer types as the pointer argument
```
This is stated as past tense ("no longer accept") but the macros still compile with integer arguments (they just produce a warning or error depending on the compiler). Be precise: "are deprecated" or "now require".
**4. Missing guidance on replacement**
The release notes say integer arguments are no longer accepted, but don't explain what to do instead. Add: "Use native operators (+, -) for integer arithmetic."
### Info
**1. Correct fixes to real bugs**
The patch fixes several real issues:
- `drivers/dma/idxd/idxd_pci.c`: Added missing `volatile` on MMIO pointer return type.
- `drivers/common/cnxk/roc_cpt_debug.c`: Preserved const on debug dump function.
- Multiple NULL checks added where `base_va` could be NULL.
These are genuine improvements.
**2. Test coverage**
The new tests in `test_common.c`:
- Verify type preservation (void, char, const void, unaligned_uint16/32/64, aligned uint16/32/64).
- Verify alignment macros (FLOOR, CEIL, default).
- Test edge cases (large alignments, address space boundaries).
This is thorough and catches the issue where pointer arithmetic preserves provenance while integer casts do not.
**3. Correct handling of unaligned types**
The test uses `unaligned_uint16_t`, `unaligned_uint32_t`, `unaligned_uint64_t` and dereferences them after `RTE_PTR_ADD`. This verifies the macro does not introduce alignment assumptions. Good.
**4. Statement expression hygiene**
The GCC/Clang implementation uses statement expressions with auto-type variables (`__rte_ptr_add`, `__rte_ptr_add_res`). The variable names are prefixed with `__rte_` to avoid collisions. However, the macros cannot nest because the inner expansion would reuse the same variable names.
**Example of nesting failure**:
```c
void *p = RTE_PTR_ADD(RTE_PTR_ADD(base, 10), 20);
```
This expands to:
```c
void *p = ({
__auto_type __rte_ptr_add = base + 0;
__auto_type __rte_ptr_add_res = ({
__auto_type __rte_ptr_add = __rte_ptr_add + 10; // SHADOWED
__auto_type __rte_ptr_add_res = ...; // SHADOWED
__rte_ptr_add_res;
}) + 0;
__auto_type __rte_ptr_add_res = ...; // REDEFINITION
__rte_ptr_add_res;
});
```
The inner expansion redefines `__rte_ptr_add` and `__rte_ptr_add_res`, causing a compiler error. The workaround is to use an intermediate variable:
```c
void *tmp = RTE_PTR_ADD(base, 10);
void *p = RTE_PTR_ADD(tmp, 20);
```
The release notes should document this limitation and provide the workaround example.
**5. MSVC fallback**
The MSVC version uses a ternary operator to preserve qualifiers:
```c
(1 ? (void *)((char *)(ptr) + (x)) : (ptr))
```
This works because:
- The ternary's type is the common type of both branches.
- If `ptr` is `const void *`, the result is `const void *`.
- The `1 ?` ensures the first branch is always taken.
This is a clever workaround for the lack of statement expressions in MSVC.
**6. Diagnostic pragmas**
The GCC/Clang version wraps the cast in:
```c
__rte_diagnostic_push
__rte_diagnostic_ignored_wcast_qual
/* cast here */
__rte_diagnostic_pop
```
This suppresses the `-Wcast-qual` warning when stripping qualifiers for the intermediate arithmetic. The ternary operator re-applies the qualifiers, so the final result is correct.
**7. Array decay**
The `+ 0` trick forces arrays to decay to pointers:
```c
char arr[10];
void *p = RTE_PTR_ADD(arr, 5);
```
Without `+ 0`, the macro would operate on the array type, which is not a pointer. The `+ 0` converts `char[10]` to `char *`.
**8. Alignment macro changes**
`RTE_PTR_ALIGN_FLOOR` and `RTE_PTR_ALIGN_CEIL` now compute the misalignment/offset and use pointer arithmetic to adjust the pointer, rather than casting to `uintptr_t`, aligning the integer, and casting back. This preserves pointer provenance and enables better compiler optimization (per the commit message).
---
## Patch 3/5: eal: make unaligned really unaligned
### Errors
None found.
### Warnings
None found.
### Info
- The patch removes the `#ifdef RTE_ARCH_STRICT_ALIGN` conditional and always defines `unaligned_uint16_t`, `unaligned_uint32_t`, and `unaligned_uint64_t` with `__rte_aligned(1)`.
- This ensures these types truly have no alignment requirement on all architectures, not just ARM strict-align variants.
- The commit message correctly notes this may cause the compiler to generate narrower loads/stores (e.g., byte-by-byte access) on architectures that trap on misaligned access.
- ARMv8 does unaligned access in hardware, so this change does not affect performance on modern ARM cores. It only matters for ARMv7 and earlier, which DPDK no longer supports in the default config.
---
## Patch 4/5: net/mlx5: drop unnecessary STRICT_ALIGN
### Errors
**1. Potential UBSAN issue not fully addressed**
The commit message states:
```
The destination is inline_data, at offset 4 of a 16 byte aligned
dseg, so the 8 byte store is always misaligned. Write it through
the unaligned type; a plain uint64_t store there is undefined
behaviour and is reported by UBSAN.
```
The fix changes:
```c
-*(uint64_t *)dst = *(unaligned_uint64_t *)src;
+*(unaligned_uint64_t *)dst = *(unaligned_uint64_t *)src;
```
This is correct: `dst` is `uintptr_t` (integer), cast to `unaligned_uint64_t *`. The cast is safe because `unaligned_uint64_t` has alignment 1.
However, the commit message says "plain uint64_t store there is undefined behaviour" but does not explain *why*. The issue is:
- `dst` is an integer (no alignment requirement).
- Casting it
More information about the test-report
mailing list