* [PATCH v6] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
@ 2026-01-14 16:07 scott.k.mitch1
2026-01-14 21:56 ` [PATCH v7] " scott.k.mitch1
0 siblings, 1 reply; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-14 16:07 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 207 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 14 ++-
3 files changed, 218 insertions(+), 4 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..5c10acc7fb
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include "test.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+
+/* Test constants for large integer types (16-bit and wider) */
+#define TEST_INITVAL_LARGE 0x1000
+#define TEST_INCREMENT_LARGE 100
+#define TEST_RETVAL_LARGE ((void *)0x1064)
+#define TEST_SUBVAL_LARGE ((void *)(TEST_INITVAL_LARGE - TEST_INCREMENT_LARGE))
+
+/* Test constants for 8-bit types */
+#define TEST_INITVAL_SMALL 100
+#define TEST_INCREMENT_SMALL 50
+#define TEST_RETVAL_SMALL ((void *)150)
+#define TEST_SUBVAL_SMALL ((void *)50)
+
+/* Test constants for bool (1-bit) */
+#define TEST_INITVAL_BOOL 1
+#define TEST_INCREMENT_BOOL 99
+#define TEST_RETVAL_BOOL ((void *)100)
+
+/* Test all C11 standard integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ unsigned long long ull = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ull, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned long long");
+ TEST_ASSERT_EQUAL(RTE_PTR_SUB(ull, TEST_INCREMENT_LARGE), TEST_SUBVAL_LARGE,
+ "RTE_PTR_SUB failed for unsigned long long");
+
+ long long ll = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ll, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for long long");
+
+ unsigned long ul = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ul, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned long");
+
+ long l = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(l, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for long");
+
+ unsigned int ui = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ui, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned int");
+
+ int i = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(i, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for int");
+
+ unsigned short us = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(us, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned short");
+
+ short s = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(s, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for short");
+
+ unsigned char uc = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(uc, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for unsigned char");
+
+ signed char sc = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(sc, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for signed char");
+
+ char c = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(c, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for char");
+
+ _Bool b = TEST_INITVAL_BOOL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(b, TEST_INCREMENT_BOOL), TEST_RETVAL_BOOL,
+ "RTE_PTR_ADD failed for _Bool");
+
+ bool b2 = TEST_INITVAL_BOOL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(b2, TEST_INCREMENT_BOOL), TEST_RETVAL_BOOL,
+ "RTE_PTR_ADD failed for bool");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[256];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(vp, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for const void*");
+ result = RTE_PTR_SUB(cvp, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for char*");
+ result = RTE_PTR_SUB(cp, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for const char*");
+ result = RTE_PTR_SUB(ccp, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for uint32_t*");
+ result = RTE_PTR_SUB(u32p, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ result = RTE_PTR_SUB(cu32p, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer - TEST_INCREMENT_SMALL),
+ "RTE_PTR_SUB failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result_const, (const void *)(buffer + TEST_INCREMENT_LARGE),
+ "RTE_PTR_ADD failed when assigning to const void*");
+
+ return 0;
+}
+
+/* Test that typedefs resolve to native types correctly */
+static int
+test_ptr_add_sub_typedefs(void)
+{
+ uint64_t u64 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u64, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u32, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint32_t");
+
+ uint16_t u16 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u16, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint16_t");
+
+ uint8_t u8 = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u8, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for uint8_t");
+
+ uintptr_t uptr = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(uptr, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(sz, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for size_t");
+
+ return 0;
+}
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ int ret;
+
+ ret = test_ptr_add_sub_integer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_pointer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_typedefs();
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, true, true, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..b525110b06 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -549,14 +549,20 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * add and subtract a byte-value offset from a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
-
+#ifdef RTE_CC_CLANG
/**
- * subtract a byte-value offset from a pointer
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
*/
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v7] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-14 16:07 [PATCH v6] eal: RTE_PTR_ADD/SUB char* for compiler optimizations scott.k.mitch1
@ 2026-01-14 21:56 ` scott.k.mitch1
2026-01-16 11:39 ` Morten Brørup
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
0 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-14 21:56 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 197 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 14 ++-
3 files changed, 208 insertions(+), 4 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..2956eabeb3
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include "test.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+
+/* Test constants for large integer types (16-bit and wider) */
+#define TEST_INITVAL_LARGE 0x1000
+#define TEST_INCREMENT_LARGE 100
+#define TEST_RETVAL_LARGE ((void *)0x1064)
+#define TEST_SUBVAL_LARGE ((void *)(TEST_INITVAL_LARGE - TEST_INCREMENT_LARGE))
+
+/* Test constants for 8-bit types */
+#define TEST_INITVAL_SMALL 100
+#define TEST_INCREMENT_SMALL 50
+#define TEST_RETVAL_SMALL ((void *)150)
+#define TEST_SUBVAL_SMALL ((void *)50)
+
+/* Test constants for bool (1-bit) */
+#define TEST_INITVAL_BOOL 1
+#define TEST_INCREMENT_BOOL 99
+#define TEST_RETVAL_BOOL ((void *)100)
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT_LARGE + TEST_INCREMENT_SMALL + 256)
+
+/* Test all C11 standard integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ unsigned long long ull = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ull, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned long long");
+ TEST_ASSERT_EQUAL(RTE_PTR_SUB(ull, TEST_INCREMENT_LARGE), TEST_SUBVAL_LARGE,
+ "RTE_PTR_SUB failed for unsigned long long");
+
+ long long ll = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ll, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for long long");
+
+ unsigned long ul = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ul, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned long");
+
+ long l = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(l, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for long");
+
+ unsigned int ui = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(ui, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned int");
+
+ int i = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(i, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for int");
+
+ unsigned short us = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(us, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for unsigned short");
+
+ short s = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(s, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for short");
+
+ unsigned char uc = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(uc, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for unsigned char");
+
+ signed char sc = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(sc, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for signed char");
+
+ char c = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(c, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for char");
+
+ _Bool b = TEST_INITVAL_BOOL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(b, TEST_INCREMENT_BOOL), TEST_RETVAL_BOOL,
+ "RTE_PTR_ADD failed for _Bool");
+
+ bool b2 = TEST_INITVAL_BOOL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(b2, TEST_INCREMENT_BOOL), TEST_RETVAL_BOOL,
+ "RTE_PTR_ADD failed for bool");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT_LARGE);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, vp, "RTE_PTR_ADD/SUB failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT_SMALL);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (const void *)cvp,
+ "RTE_PTR_ADD/SUB failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT_LARGE);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)cp, "RTE_PTR_ADD/SUB failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT_SMALL);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (const void *)ccp,
+ "RTE_PTR_ADD/SUB failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT_LARGE);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result, (void *)u32p,
+ "RTE_PTR_ADD/SUB failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT_SMALL);
+ result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
+ TEST_ASSERT_EQUAL(result, (const void *)cu32p,
+ "RTE_PTR_ADD/SUB failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT_LARGE);
+ result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT_LARGE);
+ TEST_ASSERT_EQUAL(result_const, cvp,
+ "RTE_PTR_ADD/SUB failed when assigning to const void*");
+
+ return 0;
+}
+
+/* Test that typedefs resolve to native types correctly */
+static int
+test_ptr_add_sub_typedefs(void)
+{
+ uint64_t u64 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u64, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u32, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint32_t");
+
+ uint16_t u16 = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u16, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uint16_t");
+
+ uint8_t u8 = TEST_INITVAL_SMALL;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(u8, TEST_INCREMENT_SMALL), TEST_RETVAL_SMALL,
+ "RTE_PTR_ADD failed for uint8_t");
+
+ uintptr_t uptr = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(uptr, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL_LARGE;
+ TEST_ASSERT_EQUAL(RTE_PTR_ADD(sz, TEST_INCREMENT_LARGE), TEST_RETVAL_LARGE,
+ "RTE_PTR_ADD failed for size_t");
+
+ return 0;
+}
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ int ret;
+
+ ret = test_ptr_add_sub_integer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_pointer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_typedefs();
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, true, true, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..b525110b06 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -549,14 +549,20 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * add and subtract a byte-value offset from a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
-
+#ifdef RTE_CC_CLANG
/**
- * subtract a byte-value offset from a pointer
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
*/
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [PATCH v7] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-14 21:56 ` [PATCH v7] " scott.k.mitch1
@ 2026-01-16 11:39 ` Morten Brørup
2026-01-16 22:38 ` Scott Mitchell
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
1 sibling, 1 reply; 60+ messages in thread
From: Morten Brørup @ 2026-01-16 11:39 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
> on Clang instead of uintptr_t casts. Benefits of this approach:
> - API compatibility: works for both integer and pointer inputs
> - Retains simple macros: no pragmas, no _Generic
> - Enables Clang optimizations: Clang can now unroll and vectorize
> pointer loops. GCC uses uintptr_t to avoid false positive warnings.
>
> Example use case which benefits is __rte_raw_cksum. Performance
> results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
> AVX-512) built with Clang 18.1 (TSC cycles/byte):
> Block size Before After Improvement
> 100 0.40 0.24 ~40%
> 1500 0.50 0.06 ~8x
> 9000 0.49 0.06 ~8x
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> ---
> v7:
> - Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
> - Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer
> arithmetic
> - All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to
> original)
>
> v6:
> - Make char* optimization Clang-only to avoid GCC false positive
> warnings
> - Improve tests: use named constants instead of magic numbers
> - Improve tests: use void* casts on expected values instead of
> uintptr_t on results
>
> v5:
> - Initial implementation with char* arithmetic for all compilers
>
> v4:
> - Used _Generic for type-based dispatch with char* casts
> - Had warnings on both Clang and GCC due to _Generic type-checking all
> branches
> ---
> app/test/meson.build | 1 +
> app/test/test_ptr_add_sub.c | 197 +++++++++++++++++++++++++++++++++++
> lib/eal/include/rte_common.h | 14 ++-
> 3 files changed, 208 insertions(+), 4 deletions(-)
> create mode 100644 app/test/test_ptr_add_sub.c
>
> diff --git a/app/test/meson.build b/app/test/meson.build
> index efec42a6bf..80a19d65ba 100644
> --- a/app/test/meson.build
> +++ b/app/test/meson.build
> @@ -152,6 +152,7 @@ source_file_deps = {
> 'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
> 'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
> 'test_prefetch.c': [],
> + 'test_ptr_add_sub.c': [],
> 'test_ptr_compress.c': ['ptr_compress'],
> 'test_rand_perf.c': [],
> 'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
> diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
> new file mode 100644
> index 0000000000..2956eabeb3
> --- /dev/null
> +++ b/app/test/test_ptr_add_sub.c
> @@ -0,0 +1,197 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Apple Inc.
> + */
> +
> +#include "test.h"
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +#include <rte_common.h>
> +
> +/* Test constants for large integer types (16-bit and wider) */
> +#define TEST_INITVAL_LARGE 0x1000
> +#define TEST_INCREMENT_LARGE 100
> +#define TEST_RETVAL_LARGE ((void *)0x1064)
> +#define TEST_SUBVAL_LARGE ((void *)(TEST_INITVAL_LARGE -
> TEST_INCREMENT_LARGE))
> +
> +/* Test constants for 8-bit types */
> +#define TEST_INITVAL_SMALL 100
> +#define TEST_INCREMENT_SMALL 50
> +#define TEST_RETVAL_SMALL ((void *)150)
> +#define TEST_SUBVAL_SMALL ((void *)50)
> +
> +/* Test constants for bool (1-bit) */
> +#define TEST_INITVAL_BOOL 1
> +#define TEST_INCREMENT_BOOL 99
> +#define TEST_RETVAL_BOOL ((void *)100)
TEST_RETVAL_BOOL is incorrect if typeof(ptr) is bool.
(int)(bool)(true+99) == 1
Now that _Generic is not used anymore, I suggest you remove test cases for other types than pointers.
At your preference, you may also keep pointer compatible types, i.e. 32 bit integers when building for 32-bit architecture and 64 bit integers when building for 64-bit architecture.
> +
> +/* Buffer size for pointer tests */
> +#define TEST_BUFFER_SIZE (TEST_INCREMENT_LARGE + TEST_INCREMENT_SMALL
> + 256)
> +
> +/* Test all C11 standard integer types */
> +static int
> +test_ptr_add_sub_integer_types(void)
> +{
> + unsigned long long ull = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(ull, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for unsigned long long");
> + TEST_ASSERT_EQUAL(RTE_PTR_SUB(ull, TEST_INCREMENT_LARGE),
> TEST_SUBVAL_LARGE,
> + "RTE_PTR_SUB failed for unsigned long long");
> +
> + long long ll = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(ll, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for long long");
> +
> + unsigned long ul = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(ul, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for unsigned long");
> +
> + long l = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(l, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for long");
> +
> + unsigned int ui = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(ui, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for unsigned int");
> +
> + int i = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(i, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for int");
> +
> + unsigned short us = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(us, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for unsigned short");
> +
> + short s = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(s, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for short");
> +
> + unsigned char uc = TEST_INITVAL_SMALL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(uc, TEST_INCREMENT_SMALL),
> TEST_RETVAL_SMALL,
> + "RTE_PTR_ADD failed for unsigned char");
> +
> + signed char sc = TEST_INITVAL_SMALL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(sc, TEST_INCREMENT_SMALL),
> TEST_RETVAL_SMALL,
> + "RTE_PTR_ADD failed for signed char");
> +
> + char c = TEST_INITVAL_SMALL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(c, TEST_INCREMENT_SMALL),
> TEST_RETVAL_SMALL,
> + "RTE_PTR_ADD failed for char");
> +
> + _Bool b = TEST_INITVAL_BOOL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(b, TEST_INCREMENT_BOOL),
> TEST_RETVAL_BOOL,
> + "RTE_PTR_ADD failed for _Bool");
> +
> + bool b2 = TEST_INITVAL_BOOL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(b2, TEST_INCREMENT_BOOL),
> TEST_RETVAL_BOOL,
> + "RTE_PTR_ADD failed for bool");
> +
> + return 0;
> +}
> +
> +/* Test pointer types including const correctness */
> +static int
> +test_ptr_add_sub_pointer_types(void)
> +{
> + char buffer[TEST_BUFFER_SIZE];
> + void *result;
> +
> + /* Test void* and const void* */
> + void *vp = buffer;
> + result = RTE_PTR_ADD(vp, TEST_INCREMENT_LARGE);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
> + TEST_ASSERT_EQUAL(result, vp, "RTE_PTR_ADD/SUB failed for
> void*");
> +
> + const void *cvp = buffer;
> + result = RTE_PTR_ADD(cvp, TEST_INCREMENT_SMALL);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
> + TEST_ASSERT_EQUAL(result, (const void *)cvp,
> + "RTE_PTR_ADD/SUB failed for const void*");
> +
> + /* Test char* and const char* */
> + char *cp = buffer;
> + result = RTE_PTR_ADD(cp, TEST_INCREMENT_LARGE);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
> + TEST_ASSERT_EQUAL(result, (void *)cp, "RTE_PTR_ADD/SUB failed for
> char*");
> +
> + const char *ccp = buffer;
> + result = RTE_PTR_ADD(ccp, TEST_INCREMENT_SMALL);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
> + TEST_ASSERT_EQUAL(result, (const void *)ccp,
> + "RTE_PTR_ADD/SUB failed for const char*");
> +
> + /* Test uint32_t* and const uint32_t* */
> + uint32_t *u32p = (uint32_t *)buffer;
> + result = RTE_PTR_ADD(u32p, TEST_INCREMENT_LARGE);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_LARGE);
> + TEST_ASSERT_EQUAL(result, (void *)u32p,
> + "RTE_PTR_ADD/SUB failed for uint32_t*");
> +
> + const uint32_t *cu32p = (const uint32_t *)buffer;
> + result = RTE_PTR_ADD(cu32p, TEST_INCREMENT_SMALL);
> + result = RTE_PTR_SUB(result, TEST_INCREMENT_SMALL);
> + TEST_ASSERT_EQUAL(result, (const void *)cu32p,
> + "RTE_PTR_ADD/SUB failed for const uint32_t*");
> +
> + /* Verify assigning to const pointer works (adding const is safe)
> */
> + const void *result_const = RTE_PTR_ADD(cvp,
> TEST_INCREMENT_LARGE);
> + result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT_LARGE);
> + TEST_ASSERT_EQUAL(result_const, cvp,
> + "RTE_PTR_ADD/SUB failed when assigning to const void*");
> +
> + return 0;
> +}
> +
> +/* Test that typedefs resolve to native types correctly */
> +static int
> +test_ptr_add_sub_typedefs(void)
> +{
> + uint64_t u64 = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(u64, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for uint64_t");
> +
> + uint32_t u32 = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(u32, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for uint32_t");
> +
> + uint16_t u16 = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(u16, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for uint16_t");
> +
> + uint8_t u8 = TEST_INITVAL_SMALL;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(u8, TEST_INCREMENT_SMALL),
> TEST_RETVAL_SMALL,
> + "RTE_PTR_ADD failed for uint8_t");
> +
> + uintptr_t uptr = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(uptr, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for uintptr_t");
> +
> + size_t sz = TEST_INITVAL_LARGE;
> + TEST_ASSERT_EQUAL(RTE_PTR_ADD(sz, TEST_INCREMENT_LARGE),
> TEST_RETVAL_LARGE,
> + "RTE_PTR_ADD failed for size_t");
> +
> + return 0;
> +}
> +
> +/* Main test function that runs all subtests */
> +static int
> +test_ptr_add_sub(void)
> +{
> + int ret;
> +
> + ret = test_ptr_add_sub_integer_types();
> + if (ret != 0)
> + return ret;
> +
> + ret = test_ptr_add_sub_pointer_types();
> + if (ret != 0)
> + return ret;
> +
> + ret = test_ptr_add_sub_typedefs();
> + if (ret != 0)
> + return ret;
> +
> + return 0;
> +}
> +
> +REGISTER_FAST_TEST(ptr_add_sub_autotest, true, true,
> test_ptr_add_sub);
> diff --git a/lib/eal/include/rte_common.h
> b/lib/eal/include/rte_common.h
> index 9e7d84f929..b525110b06 100644
> --- a/lib/eal/include/rte_common.h
> +++ b/lib/eal/include/rte_common.h
> @@ -549,14 +549,20 @@ static void
> __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
> /*********** Macros for pointer arithmetic ********/
>
> /**
> - * add a byte-value offset to a pointer
> + * add and subtract a byte-value offset from a pointer
> */
> -#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
> -
> +#ifdef RTE_CC_CLANG
> /**
> - * subtract a byte-value offset from a pointer
> + * Clang doesn't optimize through uintptr_t, (char*) enables
> + * optimizations and doesn't generate warnings. GCC does optimize
> + * through uintptr_t but throws warnings (e.g. array-bounds) when cast
> to char*.
> */
> +#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
> +#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
> +#else
> +#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
> #define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
> +#endif
Please keep descriptions for RTE_PTR_ADD and RTE_PTR_SUB separate, so they show up for both macros in the API documentation:
https://doc.dpdk.org/api/rte__common_8h.html#a96c6294ef6a307980f78899fe8a5813e
>
> /**
> * get the difference between two pointer values, i.e. how far apart
> --
> 2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v7] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-16 11:39 ` Morten Brørup
@ 2026-01-16 22:38 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-16 22:38 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
Feedback makes sense! I will address and submit v8.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v8] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-14 21:56 ` [PATCH v7] " scott.k.mitch1
2026-01-16 11:39 ` Morten Brørup
@ 2026-01-16 23:19 ` scott.k.mitch1
2026-01-17 2:44 ` Stephen Hemminger
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-16 23:19 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 193 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 15 ++-
3 files changed, 208 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..9674362d8d
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include "test.h"
+#include <stdint.h>
+
+#include <rte_common.h>
+
+/* Test constants for 32-bit and 64-bit integer types */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test 32-bit and 64-bit integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ void *result;
+
+ unsigned long long ull = TEST_INITVAL;
+ result = RTE_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ull,
+ "RTE_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ result = RTE_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ll,
+ "RTE_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ result = RTE_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ul,
+ "RTE_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ result = RTE_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)l,
+ "RTE_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ result = RTE_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ui,
+ "RTE_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ result = RTE_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)i,
+ "RTE_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint64_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u64,
+ "RTE_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint32_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u32,
+ "RTE_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ result = RTE_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uintptr_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)uptr,
+ "RTE_PTR_SUB round-trip failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ result = RTE_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for size_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)sz,
+ "RTE_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed when assigning to const void*");
+ result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, cvp,
+ "RTE_PTR_SUB round-trip failed when assigning to const void*");
+
+ return 0;
+}
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ int ret;
+
+ ret = test_ptr_add_sub_integer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_pointer_types();
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, true, true, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..f2935929f7 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -551,12 +551,25 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
* add a byte-value offset to a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#ifdef RTE_CC_CLANG
+/*
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
+ */
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
+#endif
/**
* subtract a byte-value offset from a pointer
*/
+#ifdef RTE_CC_CLANG
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v8] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
@ 2026-01-17 2:44 ` Stephen Hemminger
2026-01-17 21:07 ` Scott Mitchell
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
1 sibling, 1 reply; 60+ messages in thread
From: Stephen Hemminger @ 2026-01-17 2:44 UTC (permalink / raw)
To: scott.k.mitch1; +Cc: dev, mb, bruce.richardson
On Fri, 16 Jan 2026 15:19:07 -0800
scott.k.mitch1@gmail.com wrote:
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
> on Clang instead of uintptr_t casts. Benefits of this approach:
> - API compatibility: works for both integer and pointer inputs
> - Retains simple macros: no pragmas, no _Generic
> - Enables Clang optimizations: Clang can now unroll and vectorize
> pointer loops. GCC uses uintptr_t to avoid false positive warnings.
>
> Example use case which benefits is __rte_raw_cksum. Performance
> results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
> AVX-512) built with Clang 18.1 (TSC cycles/byte):
> Block size Before After Improvement
> 100 0.40 0.24 ~40%
> 1500 0.50 0.06 ~8x
> 9000 0.49 0.06 ~8x
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> ---
Looks good to me and not too complex.
AI code review had some additional comments.
## Patch Review: eal: RTE_PTR_ADD/SUB char* for compiler optimizations (v8)
### ✅ PASS Items
**Commit Message - Subject Line:**
- Length: ~52 characters (✓ under 60 limit)
- Prefix: `eal:` is correct for EAL changes
- No trailing period
- Imperative mood
**Commit Message - Body:**
- Well-documented rationale with clear performance data
- Does NOT start with "It" ✓
- Performance table shows concrete improvements (~40% to ~8x)
- Line wrapping appears within 75-character limit
**Tags:**
- `Signed-off-by:` present with real name and valid email ✓
- Tag order is correct
**SPDX/License (new file `test_ptr_add_sub.c`):**
- SPDX identifier on first line ✓
- Copyright follows SPDX ✓
- Blank line after copyright ✓
- BSD-3-Clause appropriate for `app/test` ✓
**Tests:**
- Comprehensive test coverage for integer and pointer types ✓
- Uses `TEST_ASSERT_EQUAL` macros ✓
- Uses `REGISTER_FAST_TEST` infrastructure ✓
- Tests both ADD and SUB with round-trip verification ✓
- Named constants (`TEST_INITVAL`, `TEST_INCREMENT`) instead of magic numbers ✓
**Code Quality:**
- Macro implementation is well-documented with explanatory comment
- Conditional compilation (`#ifdef RTE_CC_CLANG`) is clean
- No forbidden terminology
---
### ⚠️ WARNING Items
**1. Include Order (test_ptr_add_sub.c lines 161-164):**
```c
#include "test.h"
#include <stdint.h>
#include <rte_common.h>
```
Per AGENTS.md, order should be: (1) system includes, (2) EAL includes, (3) misc DPDK includes, (4) application-specific. Should be:
```c
#include <stdint.h>
#include <rte_common.h>
#include "test.h"
```
**2. Subject Line Contains Underscores:**
The subject `eal: RTE_PTR_ADD/SUB char* for compiler optimizations` includes underscores (code identifiers after the colon). Per AGENTS.md: "Underscores after the colon (indicates code in subject)" is flagged. Consider:
```
eal: use char pointer arithmetic for Clang optimizations
```
**3. Missing Release Notes:**
This is a notable performance optimization (~8x improvement in some cases). Per AGENTS.md, "significant changes" should update release notes in `doc/guides/rel_notes/`. Consider adding a note about the checksum performance improvement.
**4. Doxygen Documentation:**
The existing Doxygen comments for `RTE_PTR_ADD` and `RTE_PTR_SUB` remain minimal:
```c
/**
* add a byte-value offset to a pointer
*/
```
Consider adding `@param` and `@return` documentation, especially noting that `ptr` can be either a pointer or integer type.
---
### ℹ️ INFO Items (Minor Suggestions)
**1. Variable Declaration Style:**
In `test_ptr_add_sub_integer_types()`, variables are declared at point-of-use (C99 style), which is acceptable per AGENTS.md. However, `void *result` is declared at function start while type-specific variables are inline—this mixing is fine but slightly inconsistent.
**2. Test Structure:**
The tests don't use `unit_test_suite_runner` infrastructure (they use direct function calls in `test_ptr_add_sub()`). While functional, AGENTS.md suggests using `unit_test_suite_runner` for "proper integration with the DPDK test framework." This is optional since `REGISTER_FAST_TEST` is used correctly.
**3. Comment Placement:**
The implementation comment explaining Clang vs GCC behavior is placed between the Doxygen comment and the macro. This works, but having implementation notes inside a `/* ... */` block separate from Doxygen is good practice (which this patch does correctly).
---
### Summary
| Category | Status |
|----------|--------|
| Commit message format | ✅ Pass (minor subject line concern) |
| SPDX/License | ✅ Pass |
| Code style | ⚠️ Include order should be fixed |
| Tests | ✅ Pass - comprehensive |
| Documentation | ⚠️ Consider release notes |
| Compilation | Should verify independently |
**Overall Assessment:** This is a well-crafted v8 patch with solid test coverage and clear performance benefits. The main actionable items are fixing the include order and considering release notes for this optimization. The subject line concern about underscores is minor since `RTE_PTR_ADD/SUB` are canonical macro names in DPDK.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v9] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
2026-01-17 2:44 ` Stephen Hemminger
@ 2026-01-17 21:03 ` scott.k.mitch1
2026-01-18 6:12 ` Stephen Hemminger
` (2 more replies)
1 sibling, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-17 21:03 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 194 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 15 ++-
3 files changed, 209 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..5646d188ce
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants for 32-bit and 64-bit integer types */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test 32-bit and 64-bit integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ void *result;
+
+ unsigned long long ull = TEST_INITVAL;
+ result = RTE_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ull,
+ "RTE_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ result = RTE_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ll,
+ "RTE_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ result = RTE_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ul,
+ "RTE_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ result = RTE_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)l,
+ "RTE_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ result = RTE_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ui,
+ "RTE_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ result = RTE_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)i,
+ "RTE_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint64_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u64,
+ "RTE_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint32_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u32,
+ "RTE_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ result = RTE_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uintptr_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)uptr,
+ "RTE_PTR_SUB round-trip failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ result = RTE_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for size_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)sz,
+ "RTE_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed when assigning to const void*");
+ result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, cvp,
+ "RTE_PTR_SUB round-trip failed when assigning to const void*");
+
+ return 0;
+}
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ int ret;
+
+ ret = test_ptr_add_sub_integer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_pointer_types();
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..f2935929f7 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -551,12 +551,25 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
* add a byte-value offset to a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#ifdef RTE_CC_CLANG
+/*
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
+ */
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
+#endif
/**
* subtract a byte-value offset from a pointer
*/
+#ifdef RTE_CC_CLANG
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v8] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-17 2:44 ` Stephen Hemminger
@ 2026-01-17 21:07 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-17 21:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, mb, bruce.richardson
> Looks good to me and not too complex.
>
> AI code review had some additional comments.
I fixed the import order, the build failure (due to recent changes in
REGISTER_FAST_TEST), and submitted v9. Please let me know if you feel
any of the other items are blocking and must be resolved. I held off
on release notes for now as I would also like to get
https://patches.dpdk.org/project/dpdk/patch/20260112120411.27314-3-scott.k.mitch1@gmail.com/
merged which makes unaligned typedefs safe for general use and direct
pointer arithmetic (less risk of PTR ADD/SUB macros confusing
compilers as Morten also found).
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v9] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
@ 2026-01-18 6:12 ` Stephen Hemminger
2026-01-23 16:20 ` Scott Mitchell
2026-01-20 12:59 ` Morten Brørup
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2 siblings, 1 reply; 60+ messages in thread
From: Stephen Hemminger @ 2026-01-18 6:12 UTC (permalink / raw)
To: scott.k.mitch1; +Cc: dev, mb, bruce.richardson
On Sat, 17 Jan 2026 13:03:22 -0800
scott.k.mitch1@gmail.com wrote:
> +/* Main test function that runs all subtests */
> +static int
> +test_ptr_add_sub(void)
> +{
> + int ret;
> +
> + ret = test_ptr_add_sub_integer_types();
> + if (ret != 0)
> + return ret;
> +
> + ret = test_ptr_add_sub_pointer_types();
> + if (ret != 0)
> + return ret;
> +
> + return 0;
> +}
> +
Ok, but if you add more tests consider using the unit_test_runner()
in test.h. Mainly because it makes it easier to pinpoint which subtest is failing
in a big test.
^ permalink raw reply [flat|nested] 60+ messages in thread
* RE: [PATCH v9] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
2026-01-18 6:12 ` Stephen Hemminger
@ 2026-01-20 12:59 ` Morten Brørup
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: Morten Brørup @ 2026-01-20 12:59 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
Acked-by: Morten Brørup <mb@smartsharesystems.com>
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v9] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-18 6:12 ` Stephen Hemminger
@ 2026-01-23 16:20 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-23 16:20 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, mb, bruce.richardson
> Ok, but if you add more tests consider using the unit_test_runner()
> in test.h. Mainly because it makes it easier to pinpoint which subtest is failing
> in a big test.
Sounds good, v10 coming soon.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v10] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
2026-01-18 6:12 ` Stephen Hemminger
2026-01-20 12:59 ` Morten Brørup
@ 2026-01-23 16:27 ` scott.k.mitch1
2026-01-24 7:58 ` Morten Brørup
` (2 more replies)
2 siblings, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-23 16:27 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 195 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 15 ++-
3 files changed, 210 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..4169230daf
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants for 32-bit and 64-bit integer types */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test 32-bit and 64-bit integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ void *result;
+
+ unsigned long long ull = TEST_INITVAL;
+ result = RTE_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ull,
+ "RTE_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ result = RTE_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ll,
+ "RTE_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ result = RTE_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ul,
+ "RTE_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ result = RTE_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)l,
+ "RTE_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ result = RTE_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ui,
+ "RTE_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ result = RTE_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)i,
+ "RTE_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint64_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u64,
+ "RTE_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint32_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u32,
+ "RTE_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ result = RTE_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uintptr_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)uptr,
+ "RTE_PTR_SUB round-trip failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ result = RTE_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for size_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)sz,
+ "RTE_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed when assigning to const void*");
+ result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, cvp,
+ "RTE_PTR_SUB round-trip failed when assigning to const void*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_integer_types),
+ TEST_CASE(test_ptr_add_sub_pointer_types),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..f2935929f7 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -551,12 +551,25 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
* add a byte-value offset to a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#ifdef RTE_CC_CLANG
+/*
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
+ */
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
+#endif
/**
* subtract a byte-value offset from a pointer
*/
+#ifdef RTE_CC_CLANG
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [PATCH v10] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
@ 2026-01-24 7:58 ` Morten Brørup
2026-01-24 8:59 ` Scott Mitchell
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: Morten Brørup @ 2026-01-24 7:58 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
> on Clang instead of uintptr_t casts. Benefits of this approach:
> - API compatibility: works for both integer and pointer inputs
> - Retains simple macros: no pragmas, no _Generic
> - Enables Clang optimizations: Clang can now unroll and vectorize
> pointer loops. GCC uses uintptr_t to avoid false positive warnings.
>
> Example use case which benefits is __rte_raw_cksum. Performance
> results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
> AVX-512) built with Clang 18.1 (TSC cycles/byte):
> Block size Before After Improvement
> 100 0.40 0.24 ~40%
> 1500 0.50 0.06 ~8x
> 9000 0.49 0.06 ~8x
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
Acked-by: Morten Brørup <mb@smartsharesystems.com>
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v10] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2026-01-24 7:58 ` Morten Brørup
@ 2026-01-24 8:59 ` Scott Mitchell
2026-01-24 22:59 ` Scott Mitchell
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2 siblings, 1 reply; 60+ messages in thread
From: Scott Mitchell @ 2026-01-24 8:59 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson
UBSan flagged a legitimate warning [1] with this approach. There are
existing use cases in the codebase that pass ptr as NULL.
Before this change: NULL (0) is cast to uintptr_t. The addition
happens in the integer domain, which is valid defined behavior.
After this change: NULL is cast to char*. Performing arithmetic on a
NULL pointer ((char*)0 + x) is Undefined Behavior in C, even if the
offset is 0.
An example of this occurring is shown in [2].
We have a few options to resolve this:
1. Add runtime NULL checks into RTE_PTR_ADD -> Undesirable due to
runtime overhead in a hot-path macro.
2. Clarify that the caller is responsible for NULL checks -> Require
audit & update call sites in DPDK (and potentially breaking external
applications) to ensure NULL is never passed.
3. Revisit the API -> Existing API is convenient but limits type
safety, discards qualifiers (in caller code), and obscures pointer
provenance from the compiler (preventing optimizations). Here are
options to split the API:
Option 3.1: Distinct APIs per use case (Split Const/Non-Const) This
splits the macro into three explicit variants.
/* Add a byte-value offset to an integer address */
#define RTE_INT_PTR_ADD(intptr, x) ((typeof(intptr))((uintptr_t)(intptr) + (x)))
/* Add a byte-value offset to a non-const pointer */
#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(ptr) + (x)))
/* Add a byte-value offset to a const pointer */
#define RTE_CONST_PTR_ADD(ptr, x) ((const void *)((const char *)(ptr) + (x)))
Pros:
Simpler Implementation: No suppressions or casting under the hood.
Cons:
Pointer API fragmentation: Callers must manually select the right macro.
Dependency Cascade: Dependent macros like RTE_PTR_ALIGN_CEIL rely on
RTE_PTR_ADD. Splitting RTE_PTR_ADD would also split RTE_PTR_ALIGN_CEIL
(into const and non-const variants). If we change CEIL then
RTE_PTR_ALIGN_FLOOR should be considered for consistency too.
Option 3.2: Pointer API and Integer-Address API (Preferred) This
separates integer use cases but keeps a single unified macro for
pointers that preserves const correctness automatically.
/* Add a byte-value offset to an integer address */
#define RTE_INT_PTR_ADD(intptr, x) ((typeof(intptr))((uintptr_t)(intptr) + (x)))
/* Add a byte-value offset to a pointer. Returns the same type as the
input (preserving const/volatile). */
#define RTE_PTR_ADD(ptr, x) \
(__extension__ ({ \
__rte_diagnostic_push \
__rte_diagnostic_ignored_wcast_qual \
typeof(ptr) __rte_ptr_add_result = \
(typeof(ptr))((char *)(ptr) + (x)); \
__rte_diagnostic_pop \
__rte_ptr_add_result; \
}))
Pros:
Preserves Optimization: Uses char* arithmetic, allowing the compiler
to track pointer provenance.
Better Ergonomics: Callers don't need to distinguish between const and
non-const.
Existing Precedent: Following the existing pattern of RTE_PTR_ALIGN
which returns typeof(ptr).
Cons:
Requires warning suppressions: Suppressions are localized within the
macro and don't affect user code, and the typeof() return ensures type
safety at the call site.
I will submit a draft for v11 that implements option 3.2. If people
like this approach we can discuss if/how breaking into multiple
patches makes sense.
[1] ../lib/eal/common/eal_common_memory.c:335:9: runtime error:
applying zero offset to null pointer
[2] github.com/DPDK/dpdk/blob/main/lib/eal/common/eal_common_memory.c#L335
start = msl->base_va; // void* (can be NULL)
end = RTE_PTR_ADD(start, msl->len); // UB if start is NULL
if (addr >= start && addr < end)
break;
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2026-01-24 7:58 ` Morten Brørup
2026-01-24 8:59 ` Scott Mitchell
@ 2026-01-24 9:11 ` scott.k.mitch1
2026-01-25 11:11 ` scott.k.mitch1
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
2 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-24 9:11 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast to void* removes type safety and
discards qualifiers (const, volatile)
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
which are likely bugs and warrant more explicit cast/handling.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test-eventdev/test_perf_common.h | 7 +-
app/test-pmd/cmdline_flow.c | 6 +-
app/test-pmd/csumonly.c | 2 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 197 ++++++++++++++++++++
drivers/bus/pci/linux/pci_vfio.c | 2 +-
drivers/common/cnxk/cnxk_security.c | 2 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 6 +-
drivers/common/cnxk/roc_se.c | 2 +-
drivers/common/cpt/cpt_ucode_asym.h | 12 +-
drivers/common/mlx5/linux/mlx5_nl.c | 14 +-
drivers/compress/mlx5/mlx5_compress.c | 2 +-
drivers/crypto/cnxk/cn9k_cryptodev_ops.c | 2 +-
drivers/crypto/cnxk/cnxk_cryptodev_ops.c | 2 +-
drivers/crypto/mlx5/mlx5_crypto_gcm.c | 6 +-
drivers/crypto/mlx5/mlx5_crypto_xts.c | 2 +-
drivers/crypto/octeontx/otx_cryptodev_ops.c | 2 +-
drivers/dma/idxd/idxd_internal.h | 1 +
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/ml/cnxk/cn10k_ml_model.c | 2 +-
drivers/ml/cnxk/cn10k_ml_ops.c | 2 +-
drivers/ml/cnxk/cnxk_ml_ops.c | 2 +-
drivers/net/ark/ark_ethdev.c | 4 +-
drivers/net/cxgbe/cxgbe_ethdev.c | 6 +-
drivers/net/gve/base/gve_adminq.c | 12 +-
drivers/net/intel/ice/ice_tm.c | 4 +-
drivers/net/intel/ixgbe/ixgbe_rxtx.c | 2 +-
drivers/net/mlx5/mlx5_flow.c | 4 +-
drivers/net/mlx5/mlx5_flow_hw.c | 4 +-
drivers/net/mlx5/mlx5_tx.h | 4 +-
drivers/net/mlx5/mlx5_txpp.c | 4 +-
drivers/net/sfc/sfc_mae.c | 10 +-
drivers/net/virtio/virtio_rxtx.c | 2 +-
lib/eal/common/eal_common_memory.c | 19 +-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 4 +-
lib/eal/common/malloc_heap.c | 6 +-
lib/eal/include/rte_common.h | 174 ++++++++++++++++-
lib/ethdev/rte_ethdev.c | 6 +-
lib/graph/graph_populate.c | 4 +-
lib/graph/graph_stats.c | 2 +-
lib/graph/rte_graph.h | 4 +-
lib/graph/rte_graph_model_mcore_dispatch.c | 2 +-
lib/latencystats/rte_latencystats.c | 2 +-
lib/mbuf/rte_mbuf.c | 2 +-
lib/member/rte_xxh64_avx512.h | 6 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/reorder/rte_reorder.c | 2 +-
55 files changed, 502 insertions(+), 131 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-eventdev/test_perf_common.h b/app/test-eventdev/test_perf_common.h
index 365464f269..2b0434b844 100644
--- a/app/test-eventdev/test_perf_common.h
+++ b/app/test-eventdev/test_perf_common.h
@@ -141,7 +141,7 @@ perf_mark_fwd_latency(enum evt_prod_type prod_type, struct rte_event *const ev)
pe = rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- pe = RTE_PTR_ADD(op->asym->modex.result.data,
+ pe = RTE_PTR_ADD((void *)op->asym->modex.result.data,
op->asym->modex.result.length);
}
pe->timestamp = rte_get_timer_cycles();
@@ -179,7 +179,8 @@ perf_elt_from_vec_get(struct rte_event_vector *vec)
m = cop->sym->m_dst == NULL ? cop->sym->m_src : cop->sym->m_dst;
return rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- return RTE_PTR_ADD(cop->asym->modex.result.data, cop->asym->modex.result.length);
+ return RTE_PTR_ADD((void *)cop->asym->modex.result.data,
+ cop->asym->modex.result.length);
}
}
@@ -297,7 +298,7 @@ perf_process_last_stage_latency(struct rte_mempool *const pool, enum evt_prod_ty
to_free_in_bulk = m;
pe = rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- pe = RTE_PTR_ADD(op->asym->modex.result.data,
+ pe = RTE_PTR_ADD((void *)op->asym->modex.result.data,
op->asym->modex.result.length);
to_free_in_bulk = op->asym->modex.result.data;
}
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..01a45fb807 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD((void *)action->conf, arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13343,7 +13343,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
goto end;
indlst_conf->id = in->args.vc.attr.group;
indlst_conf->conf_num = in->args.vc.actions_n - 1;
- indlst_conf->actions = RTE_PTR_ADD(indlst_conf, base);
+ indlst_conf->actions = RTE_PTR_ADD((void *)indlst_conf, base);
ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, indlst_conf->actions,
len, src, NULL);
if (ret <= 0) {
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD((void *)indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index c841651756..24866e563f 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -488,7 +488,7 @@ get_ethertype_by_ptype(struct rte_ether_hdr *eth_hdr, uint32_t ptype)
return _htons(RTE_ETHER_TYPE_IPV6);
default:
ethertype = eth_hdr->ether_type;
- vlan_hdr = RTE_PTR_ADD(eth_hdr, offsetof(struct rte_ether_hdr, ether_type));
+ vlan_hdr = RTE_PTR_ADD((void *)eth_hdr, offsetof(struct rte_ether_hdr, ether_type));
max_vlans = vlan_hdr + MAX_VLAN_HEADERS;
while ((ethertype == _htons(RTE_ETHER_TYPE_VLAN) ||
ethertype == _htons(RTE_ETHER_TYPE_QINQ)) &&
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..cc0ce50bbc 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
+ "RTE_INT_PTR_ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
+ "RTE_INT_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..d7ed36e40e
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR_ADD/SUB with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset (primary use case for RTE_INT_PTR_*) */
+ uintptr_t uptr_result = RTE_INT_PTR_ADD((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR_ADD failed for NULL");
+
+ uptr_result = RTE_INT_PTR_SUB((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR_SUB failed for NULL");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = RTE_INT_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long long");
+ ull_result = RTE_INT_PTR_SUB(ull_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = RTE_INT_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long long");
+ ll_result = RTE_INT_PTR_SUB(ll_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = RTE_INT_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long");
+ ul_result = RTE_INT_PTR_SUB(ul_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = RTE_INT_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long");
+ l_result = RTE_INT_PTR_SUB(l_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = RTE_INT_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned int");
+ ui_result = RTE_INT_PTR_SUB(ui_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = RTE_INT_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for int");
+ i_result = RTE_INT_PTR_SUB(i_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = RTE_INT_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint64_t");
+ u64_result = RTE_INT_PTR_SUB(u64_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = RTE_INT_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint32_t");
+ u32_result = RTE_INT_PTR_SUB(u32_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = RTE_INT_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uintptr_t");
+ uptr_result = RTE_INT_PTR_SUB(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR_SUB failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = RTE_INT_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for size_t");
+ sz_result = RTE_INT_PTR_SUB(sz_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index 242f567ed7..004cb3cf91 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -672,7 +672,7 @@ pci_vfio_info_cap(struct vfio_region_info *info, int cap)
offset = info->cap_offset;
while (offset != 0) {
- h = RTE_PTR_ADD(info, offset);
+ h = RTE_PTR_ADD((void *)info, offset);
if (h->id == cap)
return h;
offset = h->next;
diff --git a/drivers/common/cnxk/cnxk_security.c b/drivers/common/cnxk/cnxk_security.c
index 600098ae1c..4e2105aaa6 100644
--- a/drivers/common/cnxk/cnxk_security.c
+++ b/drivers/common/cnxk/cnxk_security.c
@@ -965,7 +965,7 @@ on_fill_ipsec_common_sa(struct rte_security_ipsec_xform *ipsec,
else if (crypto_xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM) {
ccm_flag = 0x07 & ~ROC_CPT_AES_CCM_CTR_LEN;
*common_sa->iv.gcm.nonce = ccm_flag;
- memcpy(PLT_PTR_ADD(common_sa->iv.gcm.nonce, 1), &ipsec->salt, 3);
+ memcpy(PLT_PTR_ADD(&common_sa->iv.gcm.nonce[0], 1), &ipsec->salt, 3);
}
cipher_key = crypto_xform->aead.key.data;
cipher_key_len = crypto_xform->aead.key.length;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..ff27a2ede9 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD((void *)cpth, offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD((void *)cpth, offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..985b318fdd 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_PTR_ADD((void *)nix->base, off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..9fe1417756 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..d7737cb7ca 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..1bee272dde 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_INT_PTR_ADD RTE_INT_PTR_ADD
+#define PLT_INT_PTR_SUB RTE_INT_PTR_SUB
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
@@ -84,8 +86,8 @@
#define PLT_U16_CAST(val) ((uint16_t)(val))
/* Add / Sub pointer with scalar and cast to uint64_t */
-#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_ADD(__ptr, __x))
-#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_SUB(__ptr, __x))
+#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_ADD(__ptr, __x))
+#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_SUB(__ptr, __x))
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
diff --git a/drivers/common/cnxk/roc_se.c b/drivers/common/cnxk/roc_se.c
index f71832ff3a..445e2a66dc 100644
--- a/drivers/common/cnxk/roc_se.c
+++ b/drivers/common/cnxk/roc_se.c
@@ -635,7 +635,7 @@ roc_se_ctx_init(struct roc_se_ctx *roc_se_ctx)
ctx_len = PLT_ALIGN_CEIL(ctx_len, 8);
/* Skip w0 for swap */
- uc_ctx = PLT_PTR_ADD(ctx, sizeof(ctx->w0));
+ uc_ctx = PLT_PTR_ADD((void *)ctx, sizeof(ctx->w0));
for (i = 0; i < (ctx_len / 8); i++)
uc_ctx[i] = plt_cpu_to_be_64(((uint64_t *)uc_ctx)[i]);
diff --git a/drivers/common/cpt/cpt_ucode_asym.h b/drivers/common/cpt/cpt_ucode_asym.h
index 5122378ec7..85654600c8 100644
--- a/drivers/common/cpt/cpt_ucode_asym.h
+++ b/drivers/common/cpt/cpt_ucode_asym.h
@@ -251,7 +251,7 @@ cpt_modex_prep(struct asym_op_params *modex_params,
total_key_len = mod_len + exp_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, mod->modulus.data, total_key_len);
dptr += total_key_len;
memcpy(dptr, mod_op.base.data, base_len);
@@ -314,7 +314,7 @@ cpt_rsa_prep(struct asym_op_params *rsa_params,
total_key_len = mod_len + exp_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, rsa->n.data, total_key_len);
dptr += total_key_len;
@@ -399,7 +399,7 @@ cpt_rsa_crt_prep(struct asym_op_params *rsa_params,
total_key_len = p_len + q_len + dP_len + dQ_len + qInv_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, rsa->qt.q.data, total_key_len);
dptr += total_key_len;
@@ -665,7 +665,7 @@ cpt_ecdsa_sign_prep(struct rte_crypto_ecdsa_op_param *ecdsa,
pk_offset = prime_len - pkey_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
/*
* Set dlen = sum(sizeof(fpm address), ROUNDUP8(scalar len, input len),
@@ -773,7 +773,7 @@ cpt_ecdsa_verify_prep(struct rte_crypto_ecdsa_op_param *ecdsa,
s_offset = prime_len - s_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
/*
* Set dlen = sum(sizeof(fpm address), ROUNDUP8(message len),
@@ -884,7 +884,7 @@ cpt_ecpm_prep(struct rte_crypto_ecpm_op_param *ecpm,
prime_len = ec_grp[curveid].prime.length;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
p_align = RTE_ALIGN_CEIL(prime_len, 8);
scalar_align = RTE_ALIGN_CEIL(ecpm->scalar.length, 8);
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index d53543a113..65f553c20b 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1654,8 +1654,8 @@ static int
mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
{
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
for (; nla->nla_len && nla < tail;
@@ -1752,8 +1752,8 @@ mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
int ret = -EINVAL;
int *enable = arg;
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
while (nla->nla_len && nla < tail) {
@@ -2049,8 +2049,8 @@ mlx5_nl_esw_multiport_cb(struct nlmsghdr *nh, void *arg)
int ret = -EINVAL;
int *enable = arg;
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
while (nla->nla_len && nla < tail) {
@@ -2261,7 +2261,7 @@ mlx5_nl_get_mtu_bounds_cb(struct nlmsghdr *nh, void *arg)
struct mlx5_mtu *out = arg;
while (off < nh->nlmsg_len) {
- struct rtattr *ra = RTE_PTR_ADD(nh, off);
+ struct rtattr *ra = RTE_PTR_ADD((void *)nh, off);
uint32_t *payload;
switch (ra->rta_type) {
diff --git a/drivers/compress/mlx5/mlx5_compress.c b/drivers/compress/mlx5/mlx5_compress.c
index e5325c6150..cfac5dc6c1 100644
--- a/drivers/compress/mlx5/mlx5_compress.c
+++ b/drivers/compress/mlx5/mlx5_compress.c
@@ -626,7 +626,7 @@ mlx5_compress_cqe_err_handle(struct mlx5_compress_qp *qp,
qp->qp.wqes;
volatile union mlx5_gga_compress_opaque *opaq = qp->opaque_mr.addr;
- volatile uint32_t *synd_word = RTE_PTR_ADD(cqe, MLX5_ERROR_CQE_SYNDROME_OFFSET);
+ volatile uint32_t *synd_word = RTE_PTR_ADD((void *)cqe, MLX5_ERROR_CQE_SYNDROME_OFFSET);
switch (*synd_word) {
case MLX5_GGA_COMP_OUT_OF_SPACE_SYNDROME_BE:
op->status = RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
diff --git a/drivers/crypto/cnxk/cn9k_cryptodev_ops.c b/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
index 5551e40cb0..d1c68436ac 100644
--- a/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
+++ b/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
@@ -528,7 +528,7 @@ cn9k_cpt_sec_post_process(struct rte_crypto_op *cop,
hdr = rte_pktmbuf_mtod(m, struct roc_ie_on_inb_hdr *);
if (likely(m->next == NULL)) {
- ip = PLT_PTR_ADD(hdr, ROC_IE_ON_INB_RPTR_HDR);
+ ip = PLT_PTR_ADD((void *)hdr, ROC_IE_ON_INB_RPTR_HDR);
} else {
ip = (struct rte_ipv4_hdr *)hdr;
hdr = infl_req->mdata;
diff --git a/drivers/crypto/cnxk/cnxk_cryptodev_ops.c b/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
index 370f311dd3..07abeb5a52 100644
--- a/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
+++ b/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
@@ -523,7 +523,7 @@ cnxk_cpt_queue_pair_setup(struct rte_cryptodev *dev, uint16_t qp_id,
goto exit;
}
- qp->pend_q.req_queue = PLT_PTR_ADD(
+ qp->pend_q.req_queue = PLT_PTR_ADD((void *)
qp->lf.cq_vaddr, ROC_CPT_CQ_ENTRY_SIZE_UNIT << qp->lf.cq_entry_size);
}
diff --git a/drivers/crypto/mlx5/mlx5_crypto_gcm.c b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
index 89f32c7722..2c06183416 100644
--- a/drivers/crypto/mlx5/mlx5_crypto_gcm.c
+++ b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
@@ -370,7 +370,7 @@ mlx5_crypto_gcm_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
goto err;
}
qp->opaque_addr = qp->mr.addr;
- qp->klm_array = RTE_PTR_ADD(qp->opaque_addr, opaq_size);
+ qp->klm_array = RTE_PTR_ADD((void *)qp->opaque_addr, opaq_size);
/*
* Triple the CQ size as UMR QP which contains UMR and SEND_EN WQE
* will share this CQ .
@@ -733,8 +733,8 @@ static __rte_always_inline void
mlx5_crypto_gcm_build_send_en(struct mlx5_crypto_qp *qp)
{
uint32_t wqe_offset = (qp->umr_pi & (qp->umr_wqbbs - 1)) * MLX5_SEND_WQE_BB;
- struct mlx5_wqe_cseg *cs = RTE_PTR_ADD(qp->umr_qp_obj.wqes, wqe_offset);
- struct mlx5_wqe_qseg *qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ struct mlx5_wqe_cseg *cs = RTE_PTR_ADD((void *)qp->umr_qp_obj.wqes, wqe_offset);
+ struct mlx5_wqe_qseg *qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
cs->opcode = rte_cpu_to_be_32(MLX5_OPCODE_SEND_EN | ((uint32_t)qp->umr_pi << 8));
cs->sq_ds = rte_cpu_to_be_32((qp->umr_qp_obj.qp->id << 8) | 2);
diff --git a/drivers/crypto/mlx5/mlx5_crypto_xts.c b/drivers/crypto/mlx5/mlx5_crypto_xts.c
index 1c914caa85..a9f8ab2e4d 100644
--- a/drivers/crypto/mlx5/mlx5_crypto_xts.c
+++ b/drivers/crypto/mlx5/mlx5_crypto_xts.c
@@ -291,7 +291,7 @@ mlx5_crypto_xts_wqe_set(struct mlx5_crypto_priv *priv,
qp->db_pi += priv->umr_wqe_stride;
/* Set RDMA_WRITE WQE. */
cseg = RTE_PTR_ADD(cseg, priv->umr_wqe_size);
- klms = RTE_PTR_ADD(cseg, sizeof(struct mlx5_rdma_write_wqe));
+ klms = RTE_PTR_ADD((void *)cseg, sizeof(struct mlx5_rdma_write_wqe));
if (!ipl) {
klm_n = mlx5_crypto_xts_klms_set(qp, op, op->sym->m_src, klms);
if (unlikely(klm_n == 0))
diff --git a/drivers/crypto/octeontx/otx_cryptodev_ops.c b/drivers/crypto/octeontx/otx_cryptodev_ops.c
index 88657f49cc..dde216787f 100644
--- a/drivers/crypto/octeontx/otx_cryptodev_ops.c
+++ b/drivers/crypto/octeontx/otx_cryptodev_ops.c
@@ -446,7 +446,7 @@ otx_cpt_enq_single_asym(struct cpt_instance *instance,
cop[1] = (uintptr_t)op;
cop[2] = cop[3] = 0ULL;
- params.req = RTE_PTR_ADD(cop, 4 * sizeof(uintptr_t));
+ params.req = RTE_PTR_ADD((void *)cop, 4 * sizeof(uintptr_t));
params.req->op = cop;
/* Adjust meta_buf by crypto_op data and request_info struct */
diff --git a/drivers/dma/idxd/idxd_internal.h b/drivers/dma/idxd/idxd_internal.h
index b80a113455..064aeb45f3 100644
--- a/drivers/dma/idxd/idxd_internal.h
+++ b/drivers/dma/idxd/idxd_internal.h
@@ -56,6 +56,7 @@ struct idxd_dmadev {
unsigned short batch_start; /* start+size == write pointer for hdls/desc */
unsigned short batch_size;
+ /* FIXME: cast drops volatile propagation that should happen to idxd_dmadev.portal */
void *portal; /* address to write the batch descriptor */
struct idxd_completion *batch_comp_ring;
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..8109ac14b2 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -69,7 +69,7 @@ idxd_get_wq_cfg(struct idxd_pci_common *pci, uint8_t wq_idx)
static int
idxd_is_wq_enabled(struct idxd_dmadev *idxd)
{
- uint32_t state = idxd_get_wq_cfg(idxd->u.pci, idxd->qid)[wq_state_idx];
+ volatile uint32_t state = idxd_get_wq_cfg(idxd->u.pci, idxd->qid)[wq_state_idx];
return ((state >> WQ_STATE_SHIFT) & WQ_STATE_MASK) == 0x1;
}
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,8 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal */
+ idxd.portal = RTE_PTR_ADD((void *)idxd.u.pci->portals,
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..6e64998230 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -434,7 +434,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
}
for (cnt = 0; cnt < nb_cpls; cnt++) {
- cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
+ cmpl_ptr = RTE_PTR_ADD((void *)base_addr, cring_head * sizeof(cmpl));
cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
rte_memory_order_relaxed);
if (!cmpl.s.valid)
@@ -501,7 +501,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
#endif
for (cnt = 0; cnt < nb_cpls; cnt++) {
- cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
+ cmpl_ptr = RTE_PTR_ADD((void *)base_addr, cring_head * sizeof(cmpl));
cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
rte_memory_order_relaxed);
if (!cmpl.s.valid)
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/ml/cnxk/cn10k_ml_model.c b/drivers/ml/cnxk/cn10k_ml_model.c
index 12a2dda800..cb47027ee6 100644
--- a/drivers/ml/cnxk/cn10k_ml_model.c
+++ b/drivers/ml/cnxk/cn10k_ml_model.c
@@ -555,7 +555,7 @@ cn10k_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
metadata = &model->glow.metadata;
info = PLT_PTR_CAST(model->info);
- input = PLT_PTR_ADD(info, sizeof(struct rte_ml_model_info));
+ input = PLT_PTR_ADD((void *)info, sizeof(struct rte_ml_model_info));
output = PLT_PTR_ADD(input, ML_CNXK_MODEL_MAX_INPUT_OUTPUT * sizeof(struct rte_ml_io_info));
/* Set model info */
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index b30af7c7a4..8a3fcf78eb 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -702,7 +702,7 @@ cn10k_ml_layer_load(void *device, uint16_t model_id, const char *layer_name, uin
layer->glow.req = PLT_PTR_ADD(mz->addr, layer_object_size + layer_scratch_size);
/* Reset burst and sync stats */
- layer->glow.burst_xstats = PLT_PTR_ADD(
+ layer->glow.burst_xstats = PLT_PTR_ADD((void *)
layer->glow.req, PLT_ALIGN_CEIL(sizeof(struct cnxk_ml_req), ML_CN10K_ALIGN_SIZE));
for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs + 1; qp_id++) {
layer->glow.burst_xstats[qp_id].hw_latency_tot = 0;
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c
index 9958945670..ba2c4909f9 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.c
+++ b/drivers/ml/cnxk/cnxk_ml_ops.c
@@ -1211,7 +1211,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
model->cnxk_mldev = cnxk_mldev;
model->type = type;
model->model_id = lcl_model_id;
- model->info = PLT_PTR_ADD(
+ model->info = PLT_PTR_ADD((void *)
model, PLT_ALIGN_CEIL(sizeof(struct cnxk_ml_model), dev_info.align_size));
dev->data->models[lcl_model_id] = model;
diff --git a/drivers/net/ark/ark_ethdev.c b/drivers/net/ark/ark_ethdev.c
index 8b25ed948f..9c34597c81 100644
--- a/drivers/net/ark/ark_ethdev.c
+++ b/drivers/net/ark/ark_ethdev.c
@@ -713,8 +713,8 @@ ark_dev_info_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info)
{
struct ark_adapter *ark = dev->data->dev_private;
- struct ark_mpu_t *tx_mpu = RTE_PTR_ADD(ark->bar0, ARK_MPU_TX_BASE);
- struct ark_mpu_t *rx_mpu = RTE_PTR_ADD(ark->bar0, ARK_MPU_RX_BASE);
+ struct ark_mpu_t *tx_mpu = RTE_PTR_ADD((void *)ark->bar0, ARK_MPU_TX_BASE);
+ struct ark_mpu_t *rx_mpu = RTE_PTR_ADD((void *)ark->bar0, ARK_MPU_RX_BASE);
uint16_t ports = ark->num_ports;
dev_info->max_rx_pktlen = ARK_RX_MAX_PKT_LEN;
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 0c337a6cc8..f405d60449 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -940,7 +940,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
sizeof(xstats_names[count].name),
"%s", xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&ps,
+ stats_ptr = RTE_PTR_ADD((void *)&ps,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
@@ -959,7 +959,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
"tx_q%u_%s",
qid, xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&txq->stats,
+ stats_ptr = RTE_PTR_ADD((void *)&txq->stats,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
@@ -979,7 +979,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
"rx_q%u_%s",
qid, xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&rxq->stats,
+ stats_ptr = RTE_PTR_ADD((void *)&rxq->stats,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
diff --git a/drivers/net/gve/base/gve_adminq.c b/drivers/net/gve/base/gve_adminq.c
index bc1759f006..0180baefc2 100644
--- a/drivers/net/gve/base/gve_adminq.c
+++ b/drivers/net/gve/base/gve_adminq.c
@@ -75,7 +75,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI RDA");
}
- *dev_op_gqi_rda = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_gqi_rda = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_GQI_QPL:
if (option_length < sizeof(**dev_op_gqi_qpl) ||
@@ -91,7 +91,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI QPL");
}
- *dev_op_gqi_qpl = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_gqi_qpl = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_DQO_RDA:
if (option_length < sizeof(**dev_op_dqo_rda) ||
@@ -107,7 +107,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "DQO RDA");
}
- *dev_op_dqo_rda = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_dqo_rda = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_MODIFY_RING:
/* Min ring size bound is optional. */
@@ -127,7 +127,7 @@ void gve_parse_device_option(struct gve_priv *priv,
GVE_DEVICE_OPTION_TOO_BIG_FMT,
"Modify Ring");
}
- *dev_op_modify_ring = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_modify_ring = RTE_PTR_ADD((void *)option, sizeof(*option));
/* Min ring size included; set the minimum ring size. */
if (option_length == sizeof(**dev_op_modify_ring))
@@ -149,7 +149,7 @@ void gve_parse_device_option(struct gve_priv *priv,
GVE_DEVICE_OPTION_TOO_BIG_FMT,
"Jumbo Frames");
}
- *dev_op_jumbo_frames = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_jumbo_frames = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
default:
/* If we don't recognize the option just continue
@@ -175,7 +175,7 @@ gve_process_device_options(struct gve_priv *priv,
int i;
/* The options struct directly follows the device descriptor. */
- dev_opt = RTE_PTR_ADD(descriptor, sizeof(*descriptor));
+ dev_opt = RTE_PTR_ADD((void *)descriptor, sizeof(*descriptor));
for (i = 0; i < num_options; i++) {
struct gve_device_option *next_opt;
diff --git a/drivers/net/intel/ice/ice_tm.c b/drivers/net/intel/ice/ice_tm.c
index f2d8e12181..f9d86ab800 100644
--- a/drivers/net/intel/ice/ice_tm.c
+++ b/drivers/net/intel/ice/ice_tm.c
@@ -456,7 +456,7 @@ ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
tm_node->parent = NULL;
tm_node->reference_count = 0;
tm_node->shaper_profile = shaper_profile;
- tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
+ tm_node->children = RTE_PTR_ADD((void *)tm_node, sizeof(struct ice_tm_node));
tm_node->params = *params;
pf->tm_conf.root = tm_node;
return 0;
@@ -518,7 +518,7 @@ ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
tm_node->parent = parent_node;
tm_node->level = level_id;
tm_node->shaper_profile = shaper_profile;
- tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
+ tm_node->children = RTE_PTR_ADD((void *)tm_node, sizeof(struct ice_tm_node));
tm_node->parent->children[tm_node->parent->reference_count++] = tm_node;
tm_node->params = *params;
diff --git a/drivers/net/intel/ixgbe/ixgbe_rxtx.c b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
index a7583c178a..92fa9ddd96 100644
--- a/drivers/net/intel/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
@@ -2852,7 +2852,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
RTE_CACHE_LINE_SIZE, socket_id);
if (txq == NULL)
return -ENOMEM;
- txq->ctx_cache = RTE_PTR_ADD(txq, sizeof(struct ci_tx_queue));
+ txq->ctx_cache = RTE_PTR_ADD((void *)txq, sizeof(struct ci_tx_queue));
/*
* Allocate TX ring hardware descriptors. A memzone large enough to
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 2c48f1b01b..a40f5ef47a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -8326,9 +8326,9 @@ flow_alloc_thread_workspace(void)
DRV_LOG(ERR, "Failed to allocate flow workspace memory.");
return NULL;
}
- data->rss_desc.queue = RTE_PTR_ADD(data, data_size);
+ data->rss_desc.queue = RTE_PTR_ADD((void *)data, data_size);
#ifdef HAVE_MLX5_HWS_SUPPORT
- data->table = RTE_PTR_ADD(data->rss_desc.queue, rss_queue_array_size);
+ data->table = RTE_PTR_ADD((void *)data->rss_desc.queue, rss_queue_array_size);
#endif
return data;
}
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index c41b99746f..15599f47e3 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -126,7 +126,7 @@ mlx5_flow_hw_aux(uint16_t port_id, struct rte_flow_hw *flow)
if (rte_flow_template_table_resizable(port_id, &table->cfg.attr)) {
size_t offset = sizeof(struct rte_flow_hw) + mlx5dr_rule_get_handle_size();
- return RTE_PTR_ADD(flow, offset);
+ return RTE_PTR_ADD((void *)flow, offset);
} else {
return &table->flow_aux[flow->idx - 1];
}
@@ -8123,7 +8123,7 @@ __flow_hw_actions_template_create(struct rte_eth_dev *dev,
at->src_off = RTE_PTR_ADD(at->dr_off,
RTE_ALIGN(act_num * sizeof(*at->dr_off), 16));
memcpy(at->src_off, src_off, act_num * sizeof(at->src_off[0]));
- at->orig_actions = RTE_PTR_ADD(at->src_off,
+ at->orig_actions = RTE_PTR_ADD((void *)at->src_off,
RTE_ALIGN(act_num * sizeof(*at->src_off), 16));
orig_act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->orig_actions, orig_act_len,
actions, error);
diff --git a/drivers/net/mlx5/mlx5_tx.h b/drivers/net/mlx5/mlx5_tx.h
index 16307206e2..3f7bc3c607 100644
--- a/drivers/net/mlx5/mlx5_tx.h
+++ b/drivers/net/mlx5/mlx5_tx.h
@@ -897,7 +897,7 @@ mlx5_tx_qseg_init(struct mlx5_txq_data *restrict txq,
{
struct mlx5_wqe_qseg *qs;
- qs = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE);
+ qs = RTE_PTR_ADD((void *)wqe, MLX5_WSEG_SIZE);
qs->max_index = rte_cpu_to_be_32(wci);
qs->qpn_cqn = rte_cpu_to_be_32(txq->sh->txpp.clock_queue.cq_obj.cq->id);
qs->reserved0 = RTE_BE32(0);
@@ -928,7 +928,7 @@ mlx5_tx_wseg_init(struct mlx5_txq_data *restrict txq,
{
struct mlx5_wqe_wseg *ws;
- ws = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE);
+ ws = RTE_PTR_ADD((void *)wqe, MLX5_WSEG_SIZE);
ws->operation = rte_cpu_to_be_32(MLX5_WAIT_COND_CYCLIC_SMALLER);
ws->lkey = RTE_BE32(0);
ws->va_high = RTE_BE32(0);
diff --git a/drivers/net/mlx5/mlx5_txpp.c b/drivers/net/mlx5/mlx5_txpp.c
index 0e99b58bde..ac1a17476c 100644
--- a/drivers/net/mlx5/mlx5_txpp.c
+++ b/drivers/net/mlx5/mlx5_txpp.c
@@ -194,7 +194,7 @@ mlx5_txpp_fill_wqe_rearm_queue(struct mlx5_dev_ctx_shared *sh)
cs->flags = RTE_BE32(MLX5_COMP_ALWAYS <<
MLX5_COMP_MODE_OFFSET);
cs->misc = RTE_BE32(0);
- qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
index = (i * MLX5_TXPP_REARM / 2 + MLX5_TXPP_REARM) &
((1 << MLX5_WQ_INDEX_WIDTH) - 1);
qs->max_index = rte_cpu_to_be_32(index);
@@ -207,7 +207,7 @@ mlx5_txpp_fill_wqe_rearm_queue(struct mlx5_dev_ctx_shared *sh)
cs->flags = RTE_BE32(MLX5_COMP_ONLY_ERR <<
MLX5_COMP_MODE_OFFSET);
cs->misc = RTE_BE32(0);
- qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
index = (i * MLX5_TXPP_REARM / 2 + MLX5_TXPP_REARM / 2) &
((1 << MLX5_CQ_INDEX_WIDTH) - 1);
qs->max_index = rte_cpu_to_be_32(index);
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index b0e8b02b41..f31e406fb2 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -4097,7 +4097,7 @@ sfc_mae_header_force_item_masks(uint8_t *header_buf,
for (ofst = 0; ofst < proto_header_size;
ofst += sizeof(rte_be16_t)) {
- rte_be16_t *wp = RTE_PTR_ADD(header_buf, ofst);
+ rte_be16_t *wp = RTE_PTR_ADD((void *)header_buf, ofst);
const rte_be16_t *w_maskp;
const rte_be16_t *w_specp;
@@ -4231,10 +4231,10 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_vlan_hdr);
- ethertypep = RTE_PTR_ADD(buf, eth_ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, eth_ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_QINQ);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_VLAN);
ethertype_ofst =
@@ -4255,7 +4255,7 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_ipv4_hdr);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV4);
next_proto_ofst =
@@ -4274,7 +4274,7 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_ipv6_hdr);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV6);
next_proto_ofst = bounce_eh->size +
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index edecd2011f..089811160b 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -414,7 +414,7 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
iph = rte_pktmbuf_mtod_offset(m,
struct rte_ipv4_hdr *, m->l2_len);
- th = RTE_PTR_ADD(iph, m->l3_len);
+ th = RTE_PTR_ADD((void *)iph, m->l3_len);
/*
* Calculate IPv4 header checksum with current total length value
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..a1414e790c 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -332,6 +332,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +682,9 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1448,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1520,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1531,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = RTE_INT_PTR_ADD(elem_start_addr, elem->size);
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1597,7 +1597,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1609,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = RTE_INT_PTR_ADD(elem_start_addr, elem->size);
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..d62011b037 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ RTE_INT_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..22bfe96883 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -309,10 +309,10 @@ malloc_elem_from_data(const void *data)
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
+ struct malloc_elem *elem = RTE_PTR_SUB((void *)data, MALLOC_ELEM_HEADER_LEN);
if (!malloc_elem_cookies_ok(elem))
return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB((void *)elem, elem->pad);
}
/*
diff --git a/lib/eal/common/malloc_heap.c b/lib/eal/common/malloc_heap.c
index 39240c261c..bae6de58c4 100644
--- a/lib/eal/common/malloc_heap.c
+++ b/lib/eal/common/malloc_heap.c
@@ -1390,7 +1390,11 @@ malloc_heap_destroy(struct malloc_heap *heap)
/* Reset all of the heap but the (hold) lock so caller can release it. */
RTE_BUILD_BUG_ON(offsetof(struct malloc_heap, lock) != 0);
- memset(RTE_PTR_ADD(heap, sizeof(heap->lock)), 0,
+ /* Cast to void* to avoid compiler alignment assumptions from typed pointer.
+ * RTE_PTR_ADD preserves type, but heap+sizeof(lock) is misaligned for
+ * struct malloc_heap, which can cause crashes with vectorized memset.
+ */
+ memset((void *)RTE_PTR_ADD(heap, sizeof(heap->lock)), 0,
sizeof(*heap) - sizeof(heap->lock));
return 0;
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..d09704035c 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -549,14 +549,104 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to an integer representing a pointer address.
+ * Use this when working with pointer values as integers (e.g., uintptr_t),
+ * or when the pointer value may be NULL.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to add
+ * @return
+ * Result as the same type as intptr
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#define RTE_INT_PTR_ADD(intptr, x) \
+ ((typeof(intptr))((uintptr_t)(intptr) + (x)))
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from an integer representing a pointer address.
+ * Use this when working with pointer values as integers (e.g., uintptr_t),
+ * or when the pointer value may be NULL.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * Result as the same type as intptr
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#define RTE_INT_PTR_SUB(intptr, x) \
+ ((typeof(intptr))((uintptr_t)(intptr) - (x)))
+
+/**
+ * Add a byte-value offset to a pointer.
+ * Returns a pointer of the same type and const-qualification as the input.
+ *
+ * The pointer must be non-NULL for defined behavior. For NULL-safe operations
+ * or integer pointer arithmetic, use RTE_INT_PTR_ADD instead.
+ *
+ * @warning
+ * Type preservation means the compiler may assume alignment based on the
+ * returned pointer type. When doing raw memory operations (memset, memcpy)
+ * or pointer arithmetic across struct boundaries, cast the result to (void *)
+ * to prevent the compiler from making incorrect alignment assumptions that
+ * could cause crashes with vectorized instructions.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * Pointer with offset applied, preserving input type and qualifiers
+ */
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ typeof(ptr) __rte_ptr_add_result = \
+ (typeof(ptr))((char *)(ptr) + (x)); \
+ __rte_diagnostic_pop \
+ __rte_ptr_add_result; \
+}))
+#else
+#define RTE_PTR_ADD(ptr, x) ((typeof(ptr))((uintptr_t)(ptr) + (x)))
+#endif
+
+/**
+ * Subtract a byte-value offset from a pointer.
+ * Returns a pointer of the same type and const-qualification as the input.
+ *
+ * The pointer must be non-NULL for defined behavior. For NULL-safe operations
+ * or integer pointer arithmetic, use RTE_INT_PTR_SUB instead.
+ *
+ * @warning
+ * Type preservation means the compiler may assume alignment based on the
+ * returned pointer type. When doing raw memory operations (memset, memcpy)
+ * or pointer arithmetic across struct boundaries, cast the result to (void *)
+ * to prevent the compiler from making incorrect alignment assumptions that
+ * could cause crashes with vectorized instructions.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * Pointer with offset applied, preserving input type and qualifiers
+ */
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ typeof(ptr) __rte_ptr_sub_result = \
+ (typeof(ptr))((char *)(ptr) - (x)); \
+ __rte_diagnostic_pop \
+ __rte_ptr_sub_result; \
+}))
+#else
+#define RTE_PTR_SUB(ptr, x) ((typeof(ptr))((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -607,8 +697,37 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
* point to an address no higher than the first parameter. Second parameter
* must be a power-of-two value.
*/
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ __auto_type __rte_ptr_align_floor_tmp = (ptr); \
+ typeof(__rte_ptr_align_floor_tmp) __rte_ptr_align_floor_result = \
+ (typeof(__rte_ptr_align_floor_tmp)) \
+ RTE_ALIGN_FLOOR((uintptr_t)(__rte_ptr_align_floor_tmp), align); \
+ __rte_ptr_align_floor_result; \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * The resultant value will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned down to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((typeof(intptr))RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -625,8 +744,36 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
* point to an address no lower than the first parameter. Second parameter
* must be a power-of-two value.
*/
+#ifndef RTE_TOOLCHAIN_MSVC
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+(__extension__ ({ \
+ __auto_type __rte_ptr_align_ceil_tmp = (ptr); \
+ __auto_type __rte_ptr_align_tmp = RTE_PTR_ADD( \
+ __rte_ptr_align_ceil_tmp, (align) - 1); \
+ RTE_PTR_ALIGN_FLOOR(__rte_ptr_align_tmp, align); \
+}))
+#else
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * The resultant value will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned up to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((typeof(intptr))RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +793,23 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned up to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index 2659e8d9eb..05d5b52faa 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -3711,7 +3711,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* global stats */
for (i = 0; i < RTE_NB_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(ð_stats,
+ stats_ptr = RTE_PTR_ADD((void *)ð_stats,
eth_dev_stats_strings[i].offset);
val = *stats_ptr;
xstats[count++].value = val;
@@ -3723,7 +3723,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* per-rxq stats */
for (q = 0; q < nb_rxqs; q++) {
for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(&queue_stats,
+ stats_ptr = RTE_PTR_ADD((void *)&queue_stats,
eth_dev_rxq_stats_strings[i].offset +
q * sizeof(uint64_t));
val = *stats_ptr;
@@ -3734,7 +3734,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* per-txq stats */
for (q = 0; q < nb_txqs; q++) {
for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(&queue_stats,
+ stats_ptr = RTE_PTR_ADD((void *)&queue_stats,
eth_dev_txq_stats_strings[i].offset +
q * sizeof(uint64_t));
val = *stats_ptr;
diff --git a/lib/graph/graph_populate.c b/lib/graph/graph_populate.c
index 026daecb21..4ec20c26b1 100644
--- a/lib/graph/graph_populate.c
+++ b/lib/graph/graph_populate.c
@@ -62,7 +62,7 @@ graph_header_popluate(struct graph *_graph)
graph->head = (int32_t)-_graph->src_node_count;
graph->cir_mask = _graph->cir_mask;
graph->nb_nodes = _graph->node_count;
- graph->cir_start = RTE_PTR_ADD(graph, _graph->cir_start);
+ graph->cir_start = RTE_PTR_ADD((void *)graph, _graph->cir_start);
graph->nodes_start = _graph->nodes_start;
graph->socket = _graph->socket;
graph->id = _graph->id;
@@ -81,7 +81,7 @@ graph_nodes_populate(struct graph *_graph)
rte_node_t pid;
STAILQ_FOREACH(graph_node, &_graph->node_list, next) {
- struct rte_node *node = RTE_PTR_ADD(graph, off);
+ struct rte_node *node = RTE_PTR_ADD((void *)graph, off);
memset(node, 0, sizeof(*node));
node->fence = RTE_GRAPH_FENCE;
node->off = off;
diff --git a/lib/graph/graph_stats.c b/lib/graph/graph_stats.c
index b87b5707f7..e7b56966eb 100644
--- a/lib/graph/graph_stats.c
+++ b/lib/graph/graph_stats.c
@@ -501,7 +501,7 @@ cluster_node_arregate_stats(struct cluster_node *cluster, bool dispatch)
if (node->xstat_off == 0)
continue;
- xstat = RTE_PTR_ADD(node, node->xstat_off);
+ xstat = RTE_PTR_ADD((void *)node, node->xstat_off);
for (i = 0; i < stat->xstat_cntrs; i++)
stat->xstat_count[i] += xstat[i];
}
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..7eb7495eae 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD((void *)graph, off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD((void *)graph, off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/graph/rte_graph_model_mcore_dispatch.c b/lib/graph/rte_graph_model_mcore_dispatch.c
index 706b5469f0..cd3fc130d3 100644
--- a/lib/graph/rte_graph_model_mcore_dispatch.c
+++ b/lib/graph/rte_graph_model_mcore_dispatch.c
@@ -154,7 +154,7 @@ __rte_graph_mcore_dispatch_sched_wq_process(struct rte_graph *graph)
for (i = 0; i < n; i++) {
wq_node = wq_nodes[i];
- node = RTE_PTR_ADD(graph, wq_node->node_off);
+ node = RTE_PTR_ADD((void *)graph, wq_node->node_off);
RTE_ASSERT(node->fence == RTE_GRAPH_FENCE);
idx = node->idx;
free_space = node->size - idx;
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..cc27205500 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -105,7 +105,7 @@ latencystats_collect(uint64_t values[])
const uint64_t *stats;
for (i = 0; i < NUM_LATENCY_STATS; i++) {
- stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
+ stats = RTE_PTR_ADD((void *)glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
/* used to mark samples which are not a time interval */
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..61d174cba3 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -215,7 +215,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
m->next = NULL;
/* init external buffer shared info items */
- shinfo = RTE_PTR_ADD(m, mbuf_size);
+ shinfo = RTE_PTR_ADD((void *)m, mbuf_size);
m->shinfo = shinfo;
shinfo->free_cb = rte_pktmbuf_free_pinned_extmem;
shinfo->fcb_opaque = m;
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..e8251cbdbc 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD((void *)entity, sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD((void *)entity,
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD((void *)entity,
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/reorder/rte_reorder.c b/lib/reorder/rte_reorder.c
index be06530860..5caebf20d4 100644
--- a/lib/reorder/rte_reorder.c
+++ b/lib/reorder/rte_reorder.c
@@ -120,7 +120,7 @@ rte_reorder_init(struct rte_reorder_buffer *b, unsigned int bufsize,
b->order_buf.size = b->ready_buf.size = size;
b->order_buf.mask = b->ready_buf.mask = size - 1;
b->ready_buf.entries = (void *)&b[1];
- b->order_buf.entries = RTE_PTR_ADD(&b[1],
+ b->order_buf.entries = RTE_PTR_ADD((void *)&b[1],
size * sizeof(b->ready_buf.entries[0]));
return b;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v10] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
2026-01-24 8:59 ` Scott Mitchell
@ 2026-01-24 22:59 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-24 22:59 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson
> I will submit a draft for v11 that implements option 3.2. If people
> like this approach we can discuss if/how breaking into multiple
> patches makes sense.
Compilers assume memory is aligned when casting to a specific type
which isn't guaranteed when using these APIs. Returning void* prevents
compilers from making these optimizations and is a safer choice. I
will submit a v12 with APIs returning void* (I think I can still
preserve qualifiers).
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-01-25 11:11 ` scott.k.mitch1
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
1 sibling, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-25 11:11 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast to void* removes type safety and
discards qualifiers (const, volatile)
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
which are likely bugs and warrant more explicit cast/handling.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test-eventdev/test_perf_common.h | 7 +-
app/test-pmd/cmdline_flow.c | 6 +-
app/test-pmd/csumonly.c | 2 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 197 ++++++++++++++++++++
drivers/bus/pci/linux/pci_vfio.c | 2 +-
drivers/common/cnxk/cnxk_security.c | 2 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 6 +-
drivers/common/cnxk/roc_se.c | 2 +-
drivers/common/cpt/cpt_ucode_asym.h | 12 +-
drivers/common/mlx5/linux/mlx5_nl.c | 14 +-
drivers/compress/mlx5/mlx5_compress.c | 2 +-
drivers/crypto/cnxk/cn9k_cryptodev_ops.c | 2 +-
drivers/crypto/cnxk/cnxk_cryptodev_ops.c | 2 +-
drivers/crypto/mlx5/mlx5_crypto_gcm.c | 6 +-
drivers/crypto/mlx5/mlx5_crypto_xts.c | 2 +-
drivers/crypto/octeontx/otx_cryptodev_ops.c | 2 +-
drivers/dma/idxd/idxd_internal.h | 1 +
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/ml/cnxk/cn10k_ml_model.c | 2 +-
drivers/ml/cnxk/cn10k_ml_ops.c | 2 +-
drivers/ml/cnxk/cnxk_ml_ops.c | 2 +-
drivers/net/ark/ark_ethdev.c | 4 +-
drivers/net/cxgbe/cxgbe_ethdev.c | 6 +-
drivers/net/gve/base/gve_adminq.c | 12 +-
drivers/net/intel/ice/ice_tm.c | 4 +-
drivers/net/intel/ixgbe/ixgbe_rxtx.c | 2 +-
drivers/net/mlx5/mlx5_flow.c | 4 +-
drivers/net/mlx5/mlx5_flow_hw.c | 4 +-
drivers/net/mlx5/mlx5_tx.h | 4 +-
drivers/net/mlx5/mlx5_txpp.c | 4 +-
drivers/net/sfc/sfc_mae.c | 10 +-
drivers/net/virtio/virtio_rxtx.c | 2 +-
lib/eal/common/eal_common_memory.c | 19 +-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 4 +-
lib/eal/common/malloc_heap.c | 6 +-
lib/eal/include/rte_common.h | 174 ++++++++++++++++-
lib/ethdev/rte_ethdev.c | 6 +-
lib/graph/graph_populate.c | 4 +-
lib/graph/graph_stats.c | 2 +-
lib/graph/rte_graph.h | 4 +-
lib/graph/rte_graph_model_mcore_dispatch.c | 2 +-
lib/latencystats/rte_latencystats.c | 2 +-
lib/mbuf/rte_mbuf.c | 2 +-
lib/member/rte_xxh64_avx512.h | 6 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/reorder/rte_reorder.c | 2 +-
55 files changed, 502 insertions(+), 131 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-eventdev/test_perf_common.h b/app/test-eventdev/test_perf_common.h
index 365464f269..2b0434b844 100644
--- a/app/test-eventdev/test_perf_common.h
+++ b/app/test-eventdev/test_perf_common.h
@@ -141,7 +141,7 @@ perf_mark_fwd_latency(enum evt_prod_type prod_type, struct rte_event *const ev)
pe = rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- pe = RTE_PTR_ADD(op->asym->modex.result.data,
+ pe = RTE_PTR_ADD((void *)op->asym->modex.result.data,
op->asym->modex.result.length);
}
pe->timestamp = rte_get_timer_cycles();
@@ -179,7 +179,8 @@ perf_elt_from_vec_get(struct rte_event_vector *vec)
m = cop->sym->m_dst == NULL ? cop->sym->m_src : cop->sym->m_dst;
return rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- return RTE_PTR_ADD(cop->asym->modex.result.data, cop->asym->modex.result.length);
+ return RTE_PTR_ADD((void *)cop->asym->modex.result.data,
+ cop->asym->modex.result.length);
}
}
@@ -297,7 +298,7 @@ perf_process_last_stage_latency(struct rte_mempool *const pool, enum evt_prod_ty
to_free_in_bulk = m;
pe = rte_pktmbuf_mtod(m, struct perf_elt *);
} else {
- pe = RTE_PTR_ADD(op->asym->modex.result.data,
+ pe = RTE_PTR_ADD((void *)op->asym->modex.result.data,
op->asym->modex.result.length);
to_free_in_bulk = op->asym->modex.result.data;
}
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..01a45fb807 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD((void *)action->conf, arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13343,7 +13343,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
goto end;
indlst_conf->id = in->args.vc.attr.group;
indlst_conf->conf_num = in->args.vc.actions_n - 1;
- indlst_conf->actions = RTE_PTR_ADD(indlst_conf, base);
+ indlst_conf->actions = RTE_PTR_ADD((void *)indlst_conf, base);
ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, indlst_conf->actions,
len, src, NULL);
if (ret <= 0) {
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD((void *)indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index c841651756..24866e563f 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -488,7 +488,7 @@ get_ethertype_by_ptype(struct rte_ether_hdr *eth_hdr, uint32_t ptype)
return _htons(RTE_ETHER_TYPE_IPV6);
default:
ethertype = eth_hdr->ether_type;
- vlan_hdr = RTE_PTR_ADD(eth_hdr, offsetof(struct rte_ether_hdr, ether_type));
+ vlan_hdr = RTE_PTR_ADD((void *)eth_hdr, offsetof(struct rte_ether_hdr, ether_type));
max_vlans = vlan_hdr + MAX_VLAN_HEADERS;
while ((ethertype == _htons(RTE_ETHER_TYPE_VLAN) ||
ethertype == _htons(RTE_ETHER_TYPE_QINQ)) &&
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..cc0ce50bbc 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
+ "RTE_INT_PTR_ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
+ "RTE_INT_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..d7ed36e40e
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR_ADD/SUB with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset (primary use case for RTE_INT_PTR_*) */
+ uintptr_t uptr_result = RTE_INT_PTR_ADD((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR_ADD failed for NULL");
+
+ uptr_result = RTE_INT_PTR_SUB((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR_SUB failed for NULL");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = RTE_INT_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long long");
+ ull_result = RTE_INT_PTR_SUB(ull_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = RTE_INT_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long long");
+ ll_result = RTE_INT_PTR_SUB(ll_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = RTE_INT_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long");
+ ul_result = RTE_INT_PTR_SUB(ul_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = RTE_INT_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long");
+ l_result = RTE_INT_PTR_SUB(l_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = RTE_INT_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned int");
+ ui_result = RTE_INT_PTR_SUB(ui_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = RTE_INT_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for int");
+ i_result = RTE_INT_PTR_SUB(i_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = RTE_INT_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint64_t");
+ u64_result = RTE_INT_PTR_SUB(u64_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = RTE_INT_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint32_t");
+ u32_result = RTE_INT_PTR_SUB(u32_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = RTE_INT_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uintptr_t");
+ uptr_result = RTE_INT_PTR_SUB(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR_SUB failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = RTE_INT_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for size_t");
+ sz_result = RTE_INT_PTR_SUB(sz_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c
index 242f567ed7..004cb3cf91 100644
--- a/drivers/bus/pci/linux/pci_vfio.c
+++ b/drivers/bus/pci/linux/pci_vfio.c
@@ -672,7 +672,7 @@ pci_vfio_info_cap(struct vfio_region_info *info, int cap)
offset = info->cap_offset;
while (offset != 0) {
- h = RTE_PTR_ADD(info, offset);
+ h = RTE_PTR_ADD((void *)info, offset);
if (h->id == cap)
return h;
offset = h->next;
diff --git a/drivers/common/cnxk/cnxk_security.c b/drivers/common/cnxk/cnxk_security.c
index 600098ae1c..4e2105aaa6 100644
--- a/drivers/common/cnxk/cnxk_security.c
+++ b/drivers/common/cnxk/cnxk_security.c
@@ -965,7 +965,7 @@ on_fill_ipsec_common_sa(struct rte_security_ipsec_xform *ipsec,
else if (crypto_xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM) {
ccm_flag = 0x07 & ~ROC_CPT_AES_CCM_CTR_LEN;
*common_sa->iv.gcm.nonce = ccm_flag;
- memcpy(PLT_PTR_ADD(common_sa->iv.gcm.nonce, 1), &ipsec->salt, 3);
+ memcpy(PLT_PTR_ADD(&common_sa->iv.gcm.nonce[0], 1), &ipsec->salt, 3);
}
cipher_key = crypto_xform->aead.key.data;
cipher_key_len = crypto_xform->aead.key.length;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..ff27a2ede9 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD((void *)cpth, offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD((void *)cpth, offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..985b318fdd 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_PTR_ADD((void *)nix->base, off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..9fe1417756 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..d7737cb7ca 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_PTR_ADD((void *)base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..1bee272dde 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_INT_PTR_ADD RTE_INT_PTR_ADD
+#define PLT_INT_PTR_SUB RTE_INT_PTR_SUB
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
@@ -84,8 +86,8 @@
#define PLT_U16_CAST(val) ((uint16_t)(val))
/* Add / Sub pointer with scalar and cast to uint64_t */
-#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_ADD(__ptr, __x))
-#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_SUB(__ptr, __x))
+#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_ADD(__ptr, __x))
+#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_SUB(__ptr, __x))
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
diff --git a/drivers/common/cnxk/roc_se.c b/drivers/common/cnxk/roc_se.c
index f71832ff3a..445e2a66dc 100644
--- a/drivers/common/cnxk/roc_se.c
+++ b/drivers/common/cnxk/roc_se.c
@@ -635,7 +635,7 @@ roc_se_ctx_init(struct roc_se_ctx *roc_se_ctx)
ctx_len = PLT_ALIGN_CEIL(ctx_len, 8);
/* Skip w0 for swap */
- uc_ctx = PLT_PTR_ADD(ctx, sizeof(ctx->w0));
+ uc_ctx = PLT_PTR_ADD((void *)ctx, sizeof(ctx->w0));
for (i = 0; i < (ctx_len / 8); i++)
uc_ctx[i] = plt_cpu_to_be_64(((uint64_t *)uc_ctx)[i]);
diff --git a/drivers/common/cpt/cpt_ucode_asym.h b/drivers/common/cpt/cpt_ucode_asym.h
index 5122378ec7..85654600c8 100644
--- a/drivers/common/cpt/cpt_ucode_asym.h
+++ b/drivers/common/cpt/cpt_ucode_asym.h
@@ -251,7 +251,7 @@ cpt_modex_prep(struct asym_op_params *modex_params,
total_key_len = mod_len + exp_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, mod->modulus.data, total_key_len);
dptr += total_key_len;
memcpy(dptr, mod_op.base.data, base_len);
@@ -314,7 +314,7 @@ cpt_rsa_prep(struct asym_op_params *rsa_params,
total_key_len = mod_len + exp_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, rsa->n.data, total_key_len);
dptr += total_key_len;
@@ -399,7 +399,7 @@ cpt_rsa_crt_prep(struct asym_op_params *rsa_params,
total_key_len = p_len + q_len + dP_len + dQ_len + qInv_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
memcpy(dptr, rsa->qt.q.data, total_key_len);
dptr += total_key_len;
@@ -665,7 +665,7 @@ cpt_ecdsa_sign_prep(struct rte_crypto_ecdsa_op_param *ecdsa,
pk_offset = prime_len - pkey_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
/*
* Set dlen = sum(sizeof(fpm address), ROUNDUP8(scalar len, input len),
@@ -773,7 +773,7 @@ cpt_ecdsa_verify_prep(struct rte_crypto_ecdsa_op_param *ecdsa,
s_offset = prime_len - s_len;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
/*
* Set dlen = sum(sizeof(fpm address), ROUNDUP8(message len),
@@ -884,7 +884,7 @@ cpt_ecpm_prep(struct rte_crypto_ecpm_op_param *ecpm,
prime_len = ec_grp[curveid].prime.length;
/* Input buffer */
- dptr = RTE_PTR_ADD(req, sizeof(struct cpt_request_info));
+ dptr = RTE_PTR_ADD((void *)req, sizeof(struct cpt_request_info));
p_align = RTE_ALIGN_CEIL(prime_len, 8);
scalar_align = RTE_ALIGN_CEIL(ecpm->scalar.length, 8);
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index d53543a113..65f553c20b 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1654,8 +1654,8 @@ static int
mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
{
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
for (; nla->nla_len && nla < tail;
@@ -1752,8 +1752,8 @@ mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
int ret = -EINVAL;
int *enable = arg;
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
while (nla->nla_len && nla < tail) {
@@ -2049,8 +2049,8 @@ mlx5_nl_esw_multiport_cb(struct nlmsghdr *nh, void *arg)
int ret = -EINVAL;
int *enable = arg;
- struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
- struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
+ struct nlattr *tail = RTE_PTR_ADD((void *)nh, nh->nlmsg_len);
+ struct nlattr *nla = RTE_PTR_ADD((void *)nh, NLMSG_ALIGN(sizeof(*nh)) +
NLMSG_ALIGN(sizeof(struct genlmsghdr)));
while (nla->nla_len && nla < tail) {
@@ -2261,7 +2261,7 @@ mlx5_nl_get_mtu_bounds_cb(struct nlmsghdr *nh, void *arg)
struct mlx5_mtu *out = arg;
while (off < nh->nlmsg_len) {
- struct rtattr *ra = RTE_PTR_ADD(nh, off);
+ struct rtattr *ra = RTE_PTR_ADD((void *)nh, off);
uint32_t *payload;
switch (ra->rta_type) {
diff --git a/drivers/compress/mlx5/mlx5_compress.c b/drivers/compress/mlx5/mlx5_compress.c
index e5325c6150..cfac5dc6c1 100644
--- a/drivers/compress/mlx5/mlx5_compress.c
+++ b/drivers/compress/mlx5/mlx5_compress.c
@@ -626,7 +626,7 @@ mlx5_compress_cqe_err_handle(struct mlx5_compress_qp *qp,
qp->qp.wqes;
volatile union mlx5_gga_compress_opaque *opaq = qp->opaque_mr.addr;
- volatile uint32_t *synd_word = RTE_PTR_ADD(cqe, MLX5_ERROR_CQE_SYNDROME_OFFSET);
+ volatile uint32_t *synd_word = RTE_PTR_ADD((void *)cqe, MLX5_ERROR_CQE_SYNDROME_OFFSET);
switch (*synd_word) {
case MLX5_GGA_COMP_OUT_OF_SPACE_SYNDROME_BE:
op->status = RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
diff --git a/drivers/crypto/cnxk/cn9k_cryptodev_ops.c b/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
index 5551e40cb0..d1c68436ac 100644
--- a/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
+++ b/drivers/crypto/cnxk/cn9k_cryptodev_ops.c
@@ -528,7 +528,7 @@ cn9k_cpt_sec_post_process(struct rte_crypto_op *cop,
hdr = rte_pktmbuf_mtod(m, struct roc_ie_on_inb_hdr *);
if (likely(m->next == NULL)) {
- ip = PLT_PTR_ADD(hdr, ROC_IE_ON_INB_RPTR_HDR);
+ ip = PLT_PTR_ADD((void *)hdr, ROC_IE_ON_INB_RPTR_HDR);
} else {
ip = (struct rte_ipv4_hdr *)hdr;
hdr = infl_req->mdata;
diff --git a/drivers/crypto/cnxk/cnxk_cryptodev_ops.c b/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
index 370f311dd3..07abeb5a52 100644
--- a/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
+++ b/drivers/crypto/cnxk/cnxk_cryptodev_ops.c
@@ -523,7 +523,7 @@ cnxk_cpt_queue_pair_setup(struct rte_cryptodev *dev, uint16_t qp_id,
goto exit;
}
- qp->pend_q.req_queue = PLT_PTR_ADD(
+ qp->pend_q.req_queue = PLT_PTR_ADD((void *)
qp->lf.cq_vaddr, ROC_CPT_CQ_ENTRY_SIZE_UNIT << qp->lf.cq_entry_size);
}
diff --git a/drivers/crypto/mlx5/mlx5_crypto_gcm.c b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
index 89f32c7722..2c06183416 100644
--- a/drivers/crypto/mlx5/mlx5_crypto_gcm.c
+++ b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
@@ -370,7 +370,7 @@ mlx5_crypto_gcm_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
goto err;
}
qp->opaque_addr = qp->mr.addr;
- qp->klm_array = RTE_PTR_ADD(qp->opaque_addr, opaq_size);
+ qp->klm_array = RTE_PTR_ADD((void *)qp->opaque_addr, opaq_size);
/*
* Triple the CQ size as UMR QP which contains UMR and SEND_EN WQE
* will share this CQ .
@@ -733,8 +733,8 @@ static __rte_always_inline void
mlx5_crypto_gcm_build_send_en(struct mlx5_crypto_qp *qp)
{
uint32_t wqe_offset = (qp->umr_pi & (qp->umr_wqbbs - 1)) * MLX5_SEND_WQE_BB;
- struct mlx5_wqe_cseg *cs = RTE_PTR_ADD(qp->umr_qp_obj.wqes, wqe_offset);
- struct mlx5_wqe_qseg *qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ struct mlx5_wqe_cseg *cs = RTE_PTR_ADD((void *)qp->umr_qp_obj.wqes, wqe_offset);
+ struct mlx5_wqe_qseg *qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
cs->opcode = rte_cpu_to_be_32(MLX5_OPCODE_SEND_EN | ((uint32_t)qp->umr_pi << 8));
cs->sq_ds = rte_cpu_to_be_32((qp->umr_qp_obj.qp->id << 8) | 2);
diff --git a/drivers/crypto/mlx5/mlx5_crypto_xts.c b/drivers/crypto/mlx5/mlx5_crypto_xts.c
index 1c914caa85..a9f8ab2e4d 100644
--- a/drivers/crypto/mlx5/mlx5_crypto_xts.c
+++ b/drivers/crypto/mlx5/mlx5_crypto_xts.c
@@ -291,7 +291,7 @@ mlx5_crypto_xts_wqe_set(struct mlx5_crypto_priv *priv,
qp->db_pi += priv->umr_wqe_stride;
/* Set RDMA_WRITE WQE. */
cseg = RTE_PTR_ADD(cseg, priv->umr_wqe_size);
- klms = RTE_PTR_ADD(cseg, sizeof(struct mlx5_rdma_write_wqe));
+ klms = RTE_PTR_ADD((void *)cseg, sizeof(struct mlx5_rdma_write_wqe));
if (!ipl) {
klm_n = mlx5_crypto_xts_klms_set(qp, op, op->sym->m_src, klms);
if (unlikely(klm_n == 0))
diff --git a/drivers/crypto/octeontx/otx_cryptodev_ops.c b/drivers/crypto/octeontx/otx_cryptodev_ops.c
index 88657f49cc..dde216787f 100644
--- a/drivers/crypto/octeontx/otx_cryptodev_ops.c
+++ b/drivers/crypto/octeontx/otx_cryptodev_ops.c
@@ -446,7 +446,7 @@ otx_cpt_enq_single_asym(struct cpt_instance *instance,
cop[1] = (uintptr_t)op;
cop[2] = cop[3] = 0ULL;
- params.req = RTE_PTR_ADD(cop, 4 * sizeof(uintptr_t));
+ params.req = RTE_PTR_ADD((void *)cop, 4 * sizeof(uintptr_t));
params.req->op = cop;
/* Adjust meta_buf by crypto_op data and request_info struct */
diff --git a/drivers/dma/idxd/idxd_internal.h b/drivers/dma/idxd/idxd_internal.h
index b80a113455..064aeb45f3 100644
--- a/drivers/dma/idxd/idxd_internal.h
+++ b/drivers/dma/idxd/idxd_internal.h
@@ -56,6 +56,7 @@ struct idxd_dmadev {
unsigned short batch_start; /* start+size == write pointer for hdls/desc */
unsigned short batch_size;
+ /* FIXME: cast drops volatile propagation that should happen to idxd_dmadev.portal */
void *portal; /* address to write the batch descriptor */
struct idxd_completion *batch_comp_ring;
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..8109ac14b2 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -69,7 +69,7 @@ idxd_get_wq_cfg(struct idxd_pci_common *pci, uint8_t wq_idx)
static int
idxd_is_wq_enabled(struct idxd_dmadev *idxd)
{
- uint32_t state = idxd_get_wq_cfg(idxd->u.pci, idxd->qid)[wq_state_idx];
+ volatile uint32_t state = idxd_get_wq_cfg(idxd->u.pci, idxd->qid)[wq_state_idx];
return ((state >> WQ_STATE_SHIFT) & WQ_STATE_MASK) == 0x1;
}
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,8 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal */
+ idxd.portal = RTE_PTR_ADD((void *)idxd.u.pci->portals,
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..6e64998230 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -434,7 +434,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
}
for (cnt = 0; cnt < nb_cpls; cnt++) {
- cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
+ cmpl_ptr = RTE_PTR_ADD((void *)base_addr, cring_head * sizeof(cmpl));
cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
rte_memory_order_relaxed);
if (!cmpl.s.valid)
@@ -501,7 +501,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
#endif
for (cnt = 0; cnt < nb_cpls; cnt++) {
- cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
+ cmpl_ptr = RTE_PTR_ADD((void *)base_addr, cring_head * sizeof(cmpl));
cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
rte_memory_order_relaxed);
if (!cmpl.s.valid)
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/ml/cnxk/cn10k_ml_model.c b/drivers/ml/cnxk/cn10k_ml_model.c
index 12a2dda800..cb47027ee6 100644
--- a/drivers/ml/cnxk/cn10k_ml_model.c
+++ b/drivers/ml/cnxk/cn10k_ml_model.c
@@ -555,7 +555,7 @@ cn10k_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
metadata = &model->glow.metadata;
info = PLT_PTR_CAST(model->info);
- input = PLT_PTR_ADD(info, sizeof(struct rte_ml_model_info));
+ input = PLT_PTR_ADD((void *)info, sizeof(struct rte_ml_model_info));
output = PLT_PTR_ADD(input, ML_CNXK_MODEL_MAX_INPUT_OUTPUT * sizeof(struct rte_ml_io_info));
/* Set model info */
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index b30af7c7a4..8a3fcf78eb 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -702,7 +702,7 @@ cn10k_ml_layer_load(void *device, uint16_t model_id, const char *layer_name, uin
layer->glow.req = PLT_PTR_ADD(mz->addr, layer_object_size + layer_scratch_size);
/* Reset burst and sync stats */
- layer->glow.burst_xstats = PLT_PTR_ADD(
+ layer->glow.burst_xstats = PLT_PTR_ADD((void *)
layer->glow.req, PLT_ALIGN_CEIL(sizeof(struct cnxk_ml_req), ML_CN10K_ALIGN_SIZE));
for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs + 1; qp_id++) {
layer->glow.burst_xstats[qp_id].hw_latency_tot = 0;
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c
index 9958945670..ba2c4909f9 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.c
+++ b/drivers/ml/cnxk/cnxk_ml_ops.c
@@ -1211,7 +1211,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
model->cnxk_mldev = cnxk_mldev;
model->type = type;
model->model_id = lcl_model_id;
- model->info = PLT_PTR_ADD(
+ model->info = PLT_PTR_ADD((void *)
model, PLT_ALIGN_CEIL(sizeof(struct cnxk_ml_model), dev_info.align_size));
dev->data->models[lcl_model_id] = model;
diff --git a/drivers/net/ark/ark_ethdev.c b/drivers/net/ark/ark_ethdev.c
index 8b25ed948f..9c34597c81 100644
--- a/drivers/net/ark/ark_ethdev.c
+++ b/drivers/net/ark/ark_ethdev.c
@@ -713,8 +713,8 @@ ark_dev_info_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info)
{
struct ark_adapter *ark = dev->data->dev_private;
- struct ark_mpu_t *tx_mpu = RTE_PTR_ADD(ark->bar0, ARK_MPU_TX_BASE);
- struct ark_mpu_t *rx_mpu = RTE_PTR_ADD(ark->bar0, ARK_MPU_RX_BASE);
+ struct ark_mpu_t *tx_mpu = RTE_PTR_ADD((void *)ark->bar0, ARK_MPU_TX_BASE);
+ struct ark_mpu_t *rx_mpu = RTE_PTR_ADD((void *)ark->bar0, ARK_MPU_RX_BASE);
uint16_t ports = ark->num_ports;
dev_info->max_rx_pktlen = ARK_RX_MAX_PKT_LEN;
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 0c337a6cc8..f405d60449 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -940,7 +940,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
sizeof(xstats_names[count].name),
"%s", xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&ps,
+ stats_ptr = RTE_PTR_ADD((void *)&ps,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
@@ -959,7 +959,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
"tx_q%u_%s",
qid, xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&txq->stats,
+ stats_ptr = RTE_PTR_ADD((void *)&txq->stats,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
@@ -979,7 +979,7 @@ static int cxgbe_dev_xstats(struct rte_eth_dev *dev,
"rx_q%u_%s",
qid, xstats_str[i].name);
if (xstats != NULL) {
- stats_ptr = RTE_PTR_ADD(&rxq->stats,
+ stats_ptr = RTE_PTR_ADD((void *)&rxq->stats,
xstats_str[i].offset);
xstats[count].value = *stats_ptr;
xstats[count].id = count;
diff --git a/drivers/net/gve/base/gve_adminq.c b/drivers/net/gve/base/gve_adminq.c
index bc1759f006..0180baefc2 100644
--- a/drivers/net/gve/base/gve_adminq.c
+++ b/drivers/net/gve/base/gve_adminq.c
@@ -75,7 +75,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI RDA");
}
- *dev_op_gqi_rda = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_gqi_rda = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_GQI_QPL:
if (option_length < sizeof(**dev_op_gqi_qpl) ||
@@ -91,7 +91,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI QPL");
}
- *dev_op_gqi_qpl = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_gqi_qpl = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_DQO_RDA:
if (option_length < sizeof(**dev_op_dqo_rda) ||
@@ -107,7 +107,7 @@ void gve_parse_device_option(struct gve_priv *priv,
PMD_DRV_LOG(WARNING,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "DQO RDA");
}
- *dev_op_dqo_rda = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_dqo_rda = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
case GVE_DEV_OPT_ID_MODIFY_RING:
/* Min ring size bound is optional. */
@@ -127,7 +127,7 @@ void gve_parse_device_option(struct gve_priv *priv,
GVE_DEVICE_OPTION_TOO_BIG_FMT,
"Modify Ring");
}
- *dev_op_modify_ring = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_modify_ring = RTE_PTR_ADD((void *)option, sizeof(*option));
/* Min ring size included; set the minimum ring size. */
if (option_length == sizeof(**dev_op_modify_ring))
@@ -149,7 +149,7 @@ void gve_parse_device_option(struct gve_priv *priv,
GVE_DEVICE_OPTION_TOO_BIG_FMT,
"Jumbo Frames");
}
- *dev_op_jumbo_frames = RTE_PTR_ADD(option, sizeof(*option));
+ *dev_op_jumbo_frames = RTE_PTR_ADD((void *)option, sizeof(*option));
break;
default:
/* If we don't recognize the option just continue
@@ -175,7 +175,7 @@ gve_process_device_options(struct gve_priv *priv,
int i;
/* The options struct directly follows the device descriptor. */
- dev_opt = RTE_PTR_ADD(descriptor, sizeof(*descriptor));
+ dev_opt = RTE_PTR_ADD((void *)descriptor, sizeof(*descriptor));
for (i = 0; i < num_options; i++) {
struct gve_device_option *next_opt;
diff --git a/drivers/net/intel/ice/ice_tm.c b/drivers/net/intel/ice/ice_tm.c
index f2d8e12181..f9d86ab800 100644
--- a/drivers/net/intel/ice/ice_tm.c
+++ b/drivers/net/intel/ice/ice_tm.c
@@ -456,7 +456,7 @@ ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
tm_node->parent = NULL;
tm_node->reference_count = 0;
tm_node->shaper_profile = shaper_profile;
- tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
+ tm_node->children = RTE_PTR_ADD((void *)tm_node, sizeof(struct ice_tm_node));
tm_node->params = *params;
pf->tm_conf.root = tm_node;
return 0;
@@ -518,7 +518,7 @@ ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
tm_node->parent = parent_node;
tm_node->level = level_id;
tm_node->shaper_profile = shaper_profile;
- tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
+ tm_node->children = RTE_PTR_ADD((void *)tm_node, sizeof(struct ice_tm_node));
tm_node->parent->children[tm_node->parent->reference_count++] = tm_node;
tm_node->params = *params;
diff --git a/drivers/net/intel/ixgbe/ixgbe_rxtx.c b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
index a7583c178a..92fa9ddd96 100644
--- a/drivers/net/intel/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
@@ -2852,7 +2852,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
RTE_CACHE_LINE_SIZE, socket_id);
if (txq == NULL)
return -ENOMEM;
- txq->ctx_cache = RTE_PTR_ADD(txq, sizeof(struct ci_tx_queue));
+ txq->ctx_cache = RTE_PTR_ADD((void *)txq, sizeof(struct ci_tx_queue));
/*
* Allocate TX ring hardware descriptors. A memzone large enough to
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 2c48f1b01b..a40f5ef47a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -8326,9 +8326,9 @@ flow_alloc_thread_workspace(void)
DRV_LOG(ERR, "Failed to allocate flow workspace memory.");
return NULL;
}
- data->rss_desc.queue = RTE_PTR_ADD(data, data_size);
+ data->rss_desc.queue = RTE_PTR_ADD((void *)data, data_size);
#ifdef HAVE_MLX5_HWS_SUPPORT
- data->table = RTE_PTR_ADD(data->rss_desc.queue, rss_queue_array_size);
+ data->table = RTE_PTR_ADD((void *)data->rss_desc.queue, rss_queue_array_size);
#endif
return data;
}
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index c41b99746f..15599f47e3 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -126,7 +126,7 @@ mlx5_flow_hw_aux(uint16_t port_id, struct rte_flow_hw *flow)
if (rte_flow_template_table_resizable(port_id, &table->cfg.attr)) {
size_t offset = sizeof(struct rte_flow_hw) + mlx5dr_rule_get_handle_size();
- return RTE_PTR_ADD(flow, offset);
+ return RTE_PTR_ADD((void *)flow, offset);
} else {
return &table->flow_aux[flow->idx - 1];
}
@@ -8123,7 +8123,7 @@ __flow_hw_actions_template_create(struct rte_eth_dev *dev,
at->src_off = RTE_PTR_ADD(at->dr_off,
RTE_ALIGN(act_num * sizeof(*at->dr_off), 16));
memcpy(at->src_off, src_off, act_num * sizeof(at->src_off[0]));
- at->orig_actions = RTE_PTR_ADD(at->src_off,
+ at->orig_actions = RTE_PTR_ADD((void *)at->src_off,
RTE_ALIGN(act_num * sizeof(*at->src_off), 16));
orig_act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->orig_actions, orig_act_len,
actions, error);
diff --git a/drivers/net/mlx5/mlx5_tx.h b/drivers/net/mlx5/mlx5_tx.h
index 16307206e2..3f7bc3c607 100644
--- a/drivers/net/mlx5/mlx5_tx.h
+++ b/drivers/net/mlx5/mlx5_tx.h
@@ -897,7 +897,7 @@ mlx5_tx_qseg_init(struct mlx5_txq_data *restrict txq,
{
struct mlx5_wqe_qseg *qs;
- qs = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE);
+ qs = RTE_PTR_ADD((void *)wqe, MLX5_WSEG_SIZE);
qs->max_index = rte_cpu_to_be_32(wci);
qs->qpn_cqn = rte_cpu_to_be_32(txq->sh->txpp.clock_queue.cq_obj.cq->id);
qs->reserved0 = RTE_BE32(0);
@@ -928,7 +928,7 @@ mlx5_tx_wseg_init(struct mlx5_txq_data *restrict txq,
{
struct mlx5_wqe_wseg *ws;
- ws = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE);
+ ws = RTE_PTR_ADD((void *)wqe, MLX5_WSEG_SIZE);
ws->operation = rte_cpu_to_be_32(MLX5_WAIT_COND_CYCLIC_SMALLER);
ws->lkey = RTE_BE32(0);
ws->va_high = RTE_BE32(0);
diff --git a/drivers/net/mlx5/mlx5_txpp.c b/drivers/net/mlx5/mlx5_txpp.c
index 0e99b58bde..ac1a17476c 100644
--- a/drivers/net/mlx5/mlx5_txpp.c
+++ b/drivers/net/mlx5/mlx5_txpp.c
@@ -194,7 +194,7 @@ mlx5_txpp_fill_wqe_rearm_queue(struct mlx5_dev_ctx_shared *sh)
cs->flags = RTE_BE32(MLX5_COMP_ALWAYS <<
MLX5_COMP_MODE_OFFSET);
cs->misc = RTE_BE32(0);
- qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
index = (i * MLX5_TXPP_REARM / 2 + MLX5_TXPP_REARM) &
((1 << MLX5_WQ_INDEX_WIDTH) - 1);
qs->max_index = rte_cpu_to_be_32(index);
@@ -207,7 +207,7 @@ mlx5_txpp_fill_wqe_rearm_queue(struct mlx5_dev_ctx_shared *sh)
cs->flags = RTE_BE32(MLX5_COMP_ONLY_ERR <<
MLX5_COMP_MODE_OFFSET);
cs->misc = RTE_BE32(0);
- qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
+ qs = RTE_PTR_ADD((void *)cs, sizeof(struct mlx5_wqe_cseg));
index = (i * MLX5_TXPP_REARM / 2 + MLX5_TXPP_REARM / 2) &
((1 << MLX5_CQ_INDEX_WIDTH) - 1);
qs->max_index = rte_cpu_to_be_32(index);
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index b0e8b02b41..f31e406fb2 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -4097,7 +4097,7 @@ sfc_mae_header_force_item_masks(uint8_t *header_buf,
for (ofst = 0; ofst < proto_header_size;
ofst += sizeof(rte_be16_t)) {
- rte_be16_t *wp = RTE_PTR_ADD(header_buf, ofst);
+ rte_be16_t *wp = RTE_PTR_ADD((void *)header_buf, ofst);
const rte_be16_t *w_maskp;
const rte_be16_t *w_specp;
@@ -4231,10 +4231,10 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_vlan_hdr);
- ethertypep = RTE_PTR_ADD(buf, eth_ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, eth_ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_QINQ);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_VLAN);
ethertype_ofst =
@@ -4255,7 +4255,7 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_ipv4_hdr);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV4);
next_proto_ofst =
@@ -4274,7 +4274,7 @@ sfc_mae_rule_parse_action_vxlan_encap(
proto_header_size = sizeof(struct rte_ipv6_hdr);
- ethertypep = RTE_PTR_ADD(buf, ethertype_ofst);
+ ethertypep = RTE_PTR_ADD((void *)buf, ethertype_ofst);
*ethertypep = RTE_BE16(RTE_ETHER_TYPE_IPV6);
next_proto_ofst = bounce_eh->size +
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index edecd2011f..089811160b 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -414,7 +414,7 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
iph = rte_pktmbuf_mtod_offset(m,
struct rte_ipv4_hdr *, m->l2_len);
- th = RTE_PTR_ADD(iph, m->l3_len);
+ th = RTE_PTR_ADD((void *)iph, m->l3_len);
/*
* Calculate IPv4 header checksum with current total length value
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..a1414e790c 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -332,6 +332,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +682,9 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1448,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1520,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1531,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = RTE_INT_PTR_ADD(elem_start_addr, elem->size);
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1597,7 +1597,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = RTE_INT_PTR_ADD(ms_start_addr, ms->len);
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1609,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = RTE_INT_PTR_ADD(elem_start_addr, elem->size);
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..d62011b037 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ RTE_INT_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..22bfe96883 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -309,10 +309,10 @@ malloc_elem_from_data(const void *data)
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
+ struct malloc_elem *elem = RTE_PTR_SUB((void *)data, MALLOC_ELEM_HEADER_LEN);
if (!malloc_elem_cookies_ok(elem))
return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB((void *)elem, elem->pad);
}
/*
diff --git a/lib/eal/common/malloc_heap.c b/lib/eal/common/malloc_heap.c
index 39240c261c..bae6de58c4 100644
--- a/lib/eal/common/malloc_heap.c
+++ b/lib/eal/common/malloc_heap.c
@@ -1390,7 +1390,11 @@ malloc_heap_destroy(struct malloc_heap *heap)
/* Reset all of the heap but the (hold) lock so caller can release it. */
RTE_BUILD_BUG_ON(offsetof(struct malloc_heap, lock) != 0);
- memset(RTE_PTR_ADD(heap, sizeof(heap->lock)), 0,
+ /* Cast to void* to avoid compiler alignment assumptions from typed pointer.
+ * RTE_PTR_ADD preserves type, but heap+sizeof(lock) is misaligned for
+ * struct malloc_heap, which can cause crashes with vectorized memset.
+ */
+ memset((void *)RTE_PTR_ADD(heap, sizeof(heap->lock)), 0,
sizeof(*heap) - sizeof(heap->lock));
return 0;
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..d09704035c 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -549,14 +549,104 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to an integer representing a pointer address.
+ * Use this when working with pointer values as integers (e.g., uintptr_t),
+ * or when the pointer value may be NULL.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to add
+ * @return
+ * Result as the same type as intptr
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#define RTE_INT_PTR_ADD(intptr, x) \
+ ((typeof(intptr))((uintptr_t)(intptr) + (x)))
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from an integer representing a pointer address.
+ * Use this when working with pointer values as integers (e.g., uintptr_t),
+ * or when the pointer value may be NULL.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * Result as the same type as intptr
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#define RTE_INT_PTR_SUB(intptr, x) \
+ ((typeof(intptr))((uintptr_t)(intptr) - (x)))
+
+/**
+ * Add a byte-value offset to a pointer.
+ * Returns a pointer of the same type and const-qualification as the input.
+ *
+ * The pointer must be non-NULL for defined behavior. For NULL-safe operations
+ * or integer pointer arithmetic, use RTE_INT_PTR_ADD instead.
+ *
+ * @warning
+ * Type preservation means the compiler may assume alignment based on the
+ * returned pointer type. When doing raw memory operations (memset, memcpy)
+ * or pointer arithmetic across struct boundaries, cast the result to (void *)
+ * to prevent the compiler from making incorrect alignment assumptions that
+ * could cause crashes with vectorized instructions.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * Pointer with offset applied, preserving input type and qualifiers
+ */
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ typeof(ptr) __rte_ptr_add_result = \
+ (typeof(ptr))((char *)(ptr) + (x)); \
+ __rte_diagnostic_pop \
+ __rte_ptr_add_result; \
+}))
+#else
+#define RTE_PTR_ADD(ptr, x) ((typeof(ptr))((uintptr_t)(ptr) + (x)))
+#endif
+
+/**
+ * Subtract a byte-value offset from a pointer.
+ * Returns a pointer of the same type and const-qualification as the input.
+ *
+ * The pointer must be non-NULL for defined behavior. For NULL-safe operations
+ * or integer pointer arithmetic, use RTE_INT_PTR_SUB instead.
+ *
+ * @warning
+ * Type preservation means the compiler may assume alignment based on the
+ * returned pointer type. When doing raw memory operations (memset, memcpy)
+ * or pointer arithmetic across struct boundaries, cast the result to (void *)
+ * to prevent the compiler from making incorrect alignment assumptions that
+ * could cause crashes with vectorized instructions.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * Pointer with offset applied, preserving input type and qualifiers
+ */
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ typeof(ptr) __rte_ptr_sub_result = \
+ (typeof(ptr))((char *)(ptr) - (x)); \
+ __rte_diagnostic_pop \
+ __rte_ptr_sub_result; \
+}))
+#else
+#define RTE_PTR_SUB(ptr, x) ((typeof(ptr))((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -607,8 +697,37 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
* point to an address no higher than the first parameter. Second parameter
* must be a power-of-two value.
*/
+#ifndef RTE_TOOLCHAIN_MSVC
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ __auto_type __rte_ptr_align_floor_tmp = (ptr); \
+ typeof(__rte_ptr_align_floor_tmp) __rte_ptr_align_floor_result = \
+ (typeof(__rte_ptr_align_floor_tmp)) \
+ RTE_ALIGN_FLOOR((uintptr_t)(__rte_ptr_align_floor_tmp), align); \
+ __rte_ptr_align_floor_result; \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * The resultant value will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned down to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((typeof(intptr))RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -625,8 +744,36 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
* point to an address no lower than the first parameter. Second parameter
* must be a power-of-two value.
*/
+#ifndef RTE_TOOLCHAIN_MSVC
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+(__extension__ ({ \
+ __auto_type __rte_ptr_align_ceil_tmp = (ptr); \
+ __auto_type __rte_ptr_align_tmp = RTE_PTR_ADD( \
+ __rte_ptr_align_ceil_tmp, (align) - 1); \
+ RTE_PTR_ALIGN_FLOOR(__rte_ptr_align_tmp, align); \
+}))
+#else
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * The resultant value will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned up to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((typeof(intptr))RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +793,23 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * Integer address aligned up to the specified boundary
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index 2659e8d9eb..05d5b52faa 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -3711,7 +3711,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* global stats */
for (i = 0; i < RTE_NB_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(ð_stats,
+ stats_ptr = RTE_PTR_ADD((void *)ð_stats,
eth_dev_stats_strings[i].offset);
val = *stats_ptr;
xstats[count++].value = val;
@@ -3723,7 +3723,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* per-rxq stats */
for (q = 0; q < nb_rxqs; q++) {
for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(&queue_stats,
+ stats_ptr = RTE_PTR_ADD((void *)&queue_stats,
eth_dev_rxq_stats_strings[i].offset +
q * sizeof(uint64_t));
val = *stats_ptr;
@@ -3734,7 +3734,7 @@ eth_basic_stats_get(uint16_t port_id, struct rte_eth_xstat *xstats)
/* per-txq stats */
for (q = 0; q < nb_txqs; q++) {
for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
- stats_ptr = RTE_PTR_ADD(&queue_stats,
+ stats_ptr = RTE_PTR_ADD((void *)&queue_stats,
eth_dev_txq_stats_strings[i].offset +
q * sizeof(uint64_t));
val = *stats_ptr;
diff --git a/lib/graph/graph_populate.c b/lib/graph/graph_populate.c
index 026daecb21..4ec20c26b1 100644
--- a/lib/graph/graph_populate.c
+++ b/lib/graph/graph_populate.c
@@ -62,7 +62,7 @@ graph_header_popluate(struct graph *_graph)
graph->head = (int32_t)-_graph->src_node_count;
graph->cir_mask = _graph->cir_mask;
graph->nb_nodes = _graph->node_count;
- graph->cir_start = RTE_PTR_ADD(graph, _graph->cir_start);
+ graph->cir_start = RTE_PTR_ADD((void *)graph, _graph->cir_start);
graph->nodes_start = _graph->nodes_start;
graph->socket = _graph->socket;
graph->id = _graph->id;
@@ -81,7 +81,7 @@ graph_nodes_populate(struct graph *_graph)
rte_node_t pid;
STAILQ_FOREACH(graph_node, &_graph->node_list, next) {
- struct rte_node *node = RTE_PTR_ADD(graph, off);
+ struct rte_node *node = RTE_PTR_ADD((void *)graph, off);
memset(node, 0, sizeof(*node));
node->fence = RTE_GRAPH_FENCE;
node->off = off;
diff --git a/lib/graph/graph_stats.c b/lib/graph/graph_stats.c
index b87b5707f7..e7b56966eb 100644
--- a/lib/graph/graph_stats.c
+++ b/lib/graph/graph_stats.c
@@ -501,7 +501,7 @@ cluster_node_arregate_stats(struct cluster_node *cluster, bool dispatch)
if (node->xstat_off == 0)
continue;
- xstat = RTE_PTR_ADD(node, node->xstat_off);
+ xstat = RTE_PTR_ADD((void *)node, node->xstat_off);
for (i = 0; i < stat->xstat_cntrs; i++)
stat->xstat_count[i] += xstat[i];
}
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..7eb7495eae 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD((void *)graph, off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD((void *)graph, off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/graph/rte_graph_model_mcore_dispatch.c b/lib/graph/rte_graph_model_mcore_dispatch.c
index 706b5469f0..cd3fc130d3 100644
--- a/lib/graph/rte_graph_model_mcore_dispatch.c
+++ b/lib/graph/rte_graph_model_mcore_dispatch.c
@@ -154,7 +154,7 @@ __rte_graph_mcore_dispatch_sched_wq_process(struct rte_graph *graph)
for (i = 0; i < n; i++) {
wq_node = wq_nodes[i];
- node = RTE_PTR_ADD(graph, wq_node->node_off);
+ node = RTE_PTR_ADD((void *)graph, wq_node->node_off);
RTE_ASSERT(node->fence == RTE_GRAPH_FENCE);
idx = node->idx;
free_space = node->size - idx;
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..cc27205500 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -105,7 +105,7 @@ latencystats_collect(uint64_t values[])
const uint64_t *stats;
for (i = 0; i < NUM_LATENCY_STATS; i++) {
- stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
+ stats = RTE_PTR_ADD((void *)glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
/* used to mark samples which are not a time interval */
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..61d174cba3 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -215,7 +215,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
m->next = NULL;
/* init external buffer shared info items */
- shinfo = RTE_PTR_ADD(m, mbuf_size);
+ shinfo = RTE_PTR_ADD((void *)m, mbuf_size);
m->shinfo = shinfo;
shinfo->free_cb = rte_pktmbuf_free_pinned_extmem;
shinfo->fcb_opaque = m;
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..e8251cbdbc 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD((void *)entity, sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD((void *)entity,
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD((void *)entity,
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/reorder/rte_reorder.c b/lib/reorder/rte_reorder.c
index be06530860..5caebf20d4 100644
--- a/lib/reorder/rte_reorder.c
+++ b/lib/reorder/rte_reorder.c
@@ -120,7 +120,7 @@ rte_reorder_init(struct rte_reorder_buffer *b, unsigned int bufsize,
b->order_buf.size = b->ready_buf.size = size;
b->order_buf.mask = b->ready_buf.mask = size - 1;
b->ready_buf.entries = (void *)&b[1];
- b->order_buf.entries = RTE_PTR_ADD(&b[1],
+ b->order_buf.entries = RTE_PTR_ADD((void *)&b[1],
size * sizeof(b->ready_buf.entries[0]));
return b;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v12] eal: RTE_PTR_ADD/SUB API improvements
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-25 11:11 ` scott.k.mitch1
@ 2026-01-25 11:12 ` scott.k.mitch1
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-25 11:12 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
which that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 197 +++++++++++++++++++
drivers/bus/cdx/cdx_vfio.c | 6 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 7 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 9 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 2 +-
drivers/event/cnxk/cn20k_worker.c | 2 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 +--
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 8 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 206 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
43 files changed, 550 insertions(+), 99 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..83a689155f 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), (void *) BIGGER,
+ "RTE_INT_PTR_ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_SUB(BIGGER, PTR_DIFF), (void *) SMALLER,
+ "RTE_INT_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..01bf9b9785
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR_ADD/SUB with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset (primary use case for RTE_INT_PTR_*) */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR_ADD((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR_ADD failed for NULL");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR_SUB failed for NULL");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR_SUB(ull_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long long");
+ ll_result = (long long)RTE_INT_PTR_SUB(ll_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)RTE_INT_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long");
+ ul_result = (unsigned long)RTE_INT_PTR_SUB(ul_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)RTE_INT_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long");
+ l_result = (long)RTE_INT_PTR_SUB(l_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_SUB(ui_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR_SUB(i_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR_SUB(u64_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_SUB(u32_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR_SUB failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR_SUB(sz_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..5db9de3aaa 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -368,9 +368,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..05fad44581 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR_ADD(nix->base, off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..90d6aa5025 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..7061cd39ac 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..9261d26175 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,9 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR_ADD RTE_INT_PTR_ADD
+#define PLT_INT_PTR_SUB RTE_INT_PTR_SUB
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
@@ -84,8 +87,8 @@
#define PLT_U16_CAST(val) ((uint16_t)(val))
/* Add / Sub pointer with scalar and cast to uint64_t */
-#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_ADD(__ptr, __x))
-#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_SUB(__ptr, __x))
+#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_ADD(__ptr, __x))
+#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_SUB(__ptr, __x))
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..0a35a687e8 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,8 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..b596cb8702 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..e8e60d727c 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..c4e03f45f7 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1058,6 +1059,7 @@ rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
return NULL;
}
+ RTE_ASSERT(arr->data);
ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
return ret;
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..ee7054ec14 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1607,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1619,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..304a1fdce6 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,8 +79,8 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
+#define MALLOC_ELEM_TRAILER(elem) \
+ (*((const uint64_t *)RTE_PTR_ADD(elem, elem->size - MALLOC_ELEM_TRAILER_LEN)))
#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
static inline void
@@ -309,10 +309,10 @@ malloc_elem_from_data(const void *data)
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
+ struct malloc_elem *elem = RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
if (!malloc_elem_cookies_ok(elem))
return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB(elem, elem->pad);
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..fbfa0580e9 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,13 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/* C++ uses auto, C uses __auto_type for type inference */
+#ifdef __cplusplus
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
/**
* Force type alignment
*
@@ -549,14 +556,96 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
+ */
+#define RTE_INT_PTR_ADD(intptr, x) \
+ ((void *)((uintptr_t)(intptr) + (x)))
+
+/**
+ * Subtract a byte-value offset from an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#define RTE_INT_PTR_SUB(intptr, x) \
+ ((void *)((uintptr_t)(intptr) - (x)))
/**
- * subtract a byte-value offset from a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) + 0; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) + 0) + (x)) : ((ptr) + 0))
+#endif
+
+/**
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
+ */
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) + 0; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) + 0) - (x)) : ((ptr) + 0))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +691,55 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) + 0; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)((ptr) + 0), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +751,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +806,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [REVIEW] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
@ 2026-01-25 19:36 ` Stephen Hemminger
2026-01-25 22:24 ` Scott Mitchell
2026-01-26 8:19 ` Morten Brørup
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: Stephen Hemminger @ 2026-01-25 19:36 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Scott Mitchell
AI-generated review of ptr-add.mbo
Reviewed using Claude (claude-opus-4-5-20251101)
This is an automated review. Please verify all suggestions.
---
# DPDK Patch Review: eal: RTE_PTR_ADD/SUB API improvements
## Summary
This patch introduces improvements to the RTE_PTR_ADD/SUB macros by splitting the API into pointer-based and integer-based variants to preserve pointer provenance and type qualifiers.
---
## Errors (Must Fix)
### 1. Subject Line Exceeds 60 Characters
**Location:** Commit subject
**Issue:** Subject line "eal: RTE_PTR_ADD/SUB API improvements" is 39 characters, which is acceptable. However, the format should use lowercase after the colon.
**Severity:** The subject looks acceptable.
### 2. Missing Blank Line Between Tag Groups
**Location:** Commit message tags
**Issue:** The `Signed-off-by` tag appears without proper separation from the body text. According to guidelines, there should be a blank line before `Reported-by`, `Suggested-by`, `Signed-off-by` group.
**Current:**
```
...the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
```
**Expected:** Blank line separation is present, so this is acceptable.
### 3. Unnecessary Cast of void* in Test File
**Location:** `app/test/test_ptr_add_sub.c`, line 145
```c
uint32_t *u32p = (uint32_t *)buffer;
```
**Issue:** While this cast is necessary for the type conversion, consider using a union or aligned buffer to avoid potential alignment issues.
---
## Warnings (Should Fix)
### 1. Documentation Does Not Match Code for RTE_PTR_UNQUAL
**Location:** `lib/eal/include/rte_common.h`
**Issue:** The patch adds `RTE_PTR_UNQUAL` macro usage throughout the codebase but the macro definition is not shown in the patch. If this is a new macro, it needs documentation.
### 2. Use of `__auto_type` Without Fallback for All Compilers
**Location:** `lib/eal/include/rte_common.h`, lines 106-111
```c
#ifdef __cplusplus
#define __rte_auto_type auto
#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define __rte_auto_type __auto_type
#endif
```
**Issue:** No fallback defined for compilers other than GCC/Clang in C mode. This could cause compilation failures with other compilers.
### 3. Implicit Pointer Comparison
**Location:** `drivers/bus/cdx/cdx_vfio.c`, line 374
```c
if (msl->base_va == NULL)
```
**Status:** This is correct per guidelines (explicit NULL comparison).
### 4. Missing `Cc: stable@dpdk.org` Tag
**Location:** Commit message
**Issue:** This patch fixes issues that could affect existing code (compiler optimization issues, qualifier dropping). If these are considered bug fixes for stable releases, the `Cc: stable@dpdk.org` tag should be added.
### 5. Variable Declaration Style Inconsistency
**Location:** `drivers/bus/cdx/cdx_vfio.c`, lines 371-372
```c
size_t sz = msl->len;
void *end_va;
```
**Issue:** Mixed declaration styles - `sz` is initialized at declaration while `end_va` is not. Consider consistency within the function.
### 6. FIXME Comment Left in Code
**Location:** `drivers/dma/idxd/idxd_pci.c`, line 398
```c
/* FIXME: cast drops volatile propagation to idxd_dmadev.portal */
```
**Issue:** FIXME comments should be resolved before merging, or tracked in a bug tracker.
### 7. Missing Test Registration Constant Documentation
**Location:** `app/test/test_ptr_add_sub.c`, line 197
```c
REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
```
**Status:** Good - uses named constants `NOHUGE_OK` and `ASAN_OK` as required.
### 8. Inconsistent Error Handling Pattern
**Location:** Multiple files
**Issue:** Some NULL checks return early, others use goto. For example:
- `drivers/bus/cdx/cdx_vfio.c`: returns 0
- `lib/eal/linux/eal_memalloc.c`: uses goto
While both may be correct for their contexts, ensure consistency within each file.
---
## Info (Consider)
### 1. Good Practice: Using TEST_ASSERT Macros
**Location:** `app/test/test_ptr_add_sub.c`
**Status:** The test file correctly uses `TEST_ASSERT_EQUAL` and follows the `unit_test_suite_runner` pattern as required by guidelines.
### 2. Good Practice: Proper SPDX and Copyright
**Location:** `app/test/test_ptr_add_sub.c`, lines 1-3
```c
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2026 Apple Inc.
*/
```
**Status:** Correct format with SPDX on first line, copyright following, blank line before includes.
### 3. Good Practice: Include Order
**Location:** `app/test/test_ptr_add_sub.c`, lines 5-9
```c
#include <stdint.h>
#include <rte_common.h>
#include "test.h"
```
**Status:** Correct order - system includes, DPDK includes, application includes, with blank lines separating groups.
### 4. Complex Macro Implementation
**Location:** `lib/eal/include/rte_common.h`, RTE_PTR_ADD/SUB macros
**Observation:** The new implementation using `__extension__`, `__rte_auto_type`, and diagnostic pragmas is complex. Consider adding implementation notes as regular comments (which was done in v8 per changelog).
### 5. Potential ABI Impact
**Location:** `lib/eal/include/rte_common.h`
**Observation:** While these are macro changes (not ABI), the behavioral change could affect compiled code. The release notes should document this change clearly.
### 6. Line Length Compliance
**Location:** Various files
**Status:** Lines appear to be within the 100-character limit for source code.
### 7. Good Practice: Defensive NULL Checks Added
**Location:** Multiple files (`vhost_user.c`, `ena_ethdev.c`, `rte_mbuf.h`, etc.)
**Status:** The patch adds appropriate NULL checks before pointer operations, improving robustness.
### 8. Cast Style in Tests
**Location:** `app/test/test_common.c`, line 40
```c
RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), (void *) BIGGER,
```
**Note:** Space before `BIGGER` in cast `(void *) BIGGER` - minor style inconsistency but not an error.
---
## Release Notes Requirement
This patch introduces API changes (new macros, modified behavior of existing macros) and should include updates to `doc/guides/rel_notes/` for the current release noting:
- New `RTE_INT_PTR_ADD`, `RTE_INT_PTR_SUB` macros
- New `RTE_INT_PTR_ALIGN_*` macros
- New `RTE_PTR_UNQUAL` macro (if defined in this patch)
- Modified behavior of `RTE_PTR_ADD`/`RTE_PTR_SUB` to preserve qualifiers
---
## Overall Assessment
The patch is well-structured and addresses real issues with pointer provenance and qualifier preservation. The test coverage is good, following DPDK test framework conventions. Main concerns are:
1. Missing definition/documentation for `RTE_PTR_UNQUAL` macro
2. FIXME comment should be resolved
3. Release notes should be updated for API changes
4. Consider adding fallback for `__rte_auto_type` for non-GCC/Clang compilers
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [REVIEW] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
@ 2026-01-25 22:24 ` Scott Mitchell
2026-01-26 8:19 ` Morten Brørup
1 sibling, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-25 22:24 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev
v13 coming soon addressing the relevant comments and some compilation
warnings on newer compilers.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v13] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
@ 2026-01-25 22:30 ` scott.k.mitch1
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
2026-01-27 20:28 ` [REVIEW] " Stephen Hemminger
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-25 22:30 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
___
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 ++++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 7 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 2 +-
drivers/event/cnxk/cn20k_worker.c | 2 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 20 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 219 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
44 files changed, 594 insertions(+), 102 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..299700f84b 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), (void *)BIGGER,
+ "RTE_INT_PTR_ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_SUB(BIGGER, PTR_DIFF), (void *)SMALLER,
+ "RTE_INT_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..ffd3f78ca6
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR_ADD/SUB with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset (primary use case for RTE_INT_PTR_*) */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR_ADD((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR_ADD failed for NULL");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR_SUB failed for NULL");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR_SUB(ull_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long long");
+ ll_result = (long long)RTE_INT_PTR_SUB(ll_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)RTE_INT_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long");
+ ul_result = (unsigned long)RTE_INT_PTR_SUB(ul_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)RTE_INT_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long");
+ l_result = (long)RTE_INT_PTR_SUB(l_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_SUB(ui_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR_SUB(i_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR_SUB(u64_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_SUB(u32_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR_SUB failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR_SUB(sz_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ /* Align buffer for uint32_t access to avoid alignment issues */
+ alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..1a793204d0 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,17 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD`` and ``RTE_PTR_SUB`` now preserve const/volatile qualifiers
+ and use pointer arithmetic instead of integer casts to enable compiler optimizations.
+ * Passing NULL to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB`` is now undefined behavior.
+ * Added ``RTE_INT_PTR_ADD`` and ``RTE_INT_PTR_SUB`` for integer-as-pointer arithmetic.
+ * Added ``RTE_INT_PTR_ALIGN``, ``RTE_INT_PTR_ALIGN_FLOOR``, and ``RTE_INT_PTR_ALIGN_CEIL``
+ for aligning integer addresses.
+ * Existing code using ``RTE_PTR_ADD``/``RTE_PTR_SUB`` with integer types should migrate
+ to ``RTE_INT_PTR_*`` variants for clarity and correctness.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..05fad44581 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR_ADD(nix->base, off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..90d6aa5025 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..7061cd39ac 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..9261d26175 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,9 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR_ADD RTE_INT_PTR_ADD
+#define PLT_INT_PTR_SUB RTE_INT_PTR_SUB
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
@@ -84,8 +87,8 @@
#define PLT_U16_CAST(val) ((uint16_t)(val))
/* Add / Sub pointer with scalar and cast to uint64_t */
-#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_ADD(__ptr, __x))
-#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_SUB(__ptr, __x))
+#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_ADD(__ptr, __x))
+#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_SUB(__ptr, __x))
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..b596cb8702 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..e8e60d727c 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..c4e03f45f7 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1058,6 +1059,7 @@ rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
return NULL;
}
+ RTE_ASSERT(arr->data);
ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
return ret;
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..ee7054ec14 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1607,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1619,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..cba2c4467b 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,8 +79,8 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
+#define MALLOC_ELEM_TRAILER(elem) \
+ (*((uint64_t *)RTE_PTR_ADD(elem, elem->size - MALLOC_ELEM_TRAILER_LEN)))
#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
static inline void
@@ -103,7 +103,7 @@ malloc_elem_cookies_ok(const struct malloc_elem *elem)
{
return elem != NULL &&
MALLOC_ELEM_HEADER(elem) == MALLOC_HEADER_COOKIE &&
- MALLOC_ELEM_TRAILER(elem) == MALLOC_TRAILER_COOKIE;
+ MALLOC_ELEM_TRAILER(RTE_PTR_UNQUAL(elem)) == MALLOC_TRAILER_COOKIE;
}
#endif
@@ -309,10 +309,20 @@ malloc_elem_from_data(const void *data)
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
+ /* rte_malloc_socket pool layout: [pad if ELEM_PAD][header][user data][trailer].
+ * The pointer 'data' points to user data, but the compiler can't trace this
+ * through the allocation function. GCC's interprocedural analysis issues a
+ * false positive warning when accessing the header via backwards pointer arithmetic.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ struct malloc_elem *elem = RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
if (!malloc_elem_cookies_ok(elem))
return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+
+ return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB(elem, elem->pad);
+ __rte_diagnostic_pop
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..4378b28018 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,16 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +220,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +569,96 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
+ */
+#define RTE_INT_PTR_ADD(intptr, x) \
+ ((void *)((uintptr_t)(intptr) + (x)))
+
+/**
+ * Subtract a byte-value offset from an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
+ */
+#define RTE_INT_PTR_SUB(intptr, x) \
+ ((void *)((uintptr_t)(intptr) - (x)))
+
+/**
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) + 0; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) + 0) + (x)) : ((ptr) + 0))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) + 0; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) + 0) - (x)) : ((ptr) + 0))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +704,55 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) + 0; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)((ptr) + 0), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +764,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +819,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v14] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
@ 2026-01-26 8:03 ` scott.k.mitch1
2026-01-26 14:35 ` Morten Brørup
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
2026-01-27 20:28 ` [REVIEW] " Stephen Hemminger
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-26 8:03 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 ++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 7 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 242 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
44 files changed, 659 insertions(+), 134 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..299700f84b 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_ADD(SMALLER, PTR_DIFF), (void *)BIGGER,
+ "RTE_INT_PTR_ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR_SUB(BIGGER, PTR_DIFF), (void *)SMALLER,
+ "RTE_INT_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..7d1a08ce48
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR_ADD/SUB with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset (primary use case for RTE_INT_PTR_*) */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR_ADD((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR_ADD failed for NULL");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB((uintptr_t)NULL, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR_SUB failed for NULL");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR_SUB(ull_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long long");
+ ll_result = (long long)RTE_INT_PTR_SUB(ll_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned long");
+ ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR_SUB(ul_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)(uintptr_t)RTE_INT_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for long");
+ l_result = (long)(uintptr_t)RTE_INT_PTR_SUB(l_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR_SUB(ui_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR_SUB(i_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR_SUB(u64_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR_SUB(u32_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR_SUB(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR_SUB failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR_ADD failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR_SUB(sz_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ /* Align buffer for uint32_t access to avoid alignment issues */
+ alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..1a793204d0 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,17 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD`` and ``RTE_PTR_SUB`` now preserve const/volatile qualifiers
+ and use pointer arithmetic instead of integer casts to enable compiler optimizations.
+ * Passing NULL to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB`` is now undefined behavior.
+ * Added ``RTE_INT_PTR_ADD`` and ``RTE_INT_PTR_SUB`` for integer-as-pointer arithmetic.
+ * Added ``RTE_INT_PTR_ALIGN``, ``RTE_INT_PTR_ALIGN_FLOOR``, and ``RTE_INT_PTR_ALIGN_CEIL``
+ for aligning integer addresses.
+ * Existing code using ``RTE_PTR_ADD``/``RTE_PTR_SUB`` with integer types should migrate
+ to ``RTE_INT_PTR_*`` variants for clarity and correctness.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..05fad44581 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR_ADD(nix->base, off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..90d6aa5025 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..7061cd39ac 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR_ADD(base, off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..9261d26175 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,9 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR_ADD RTE_INT_PTR_ADD
+#define PLT_INT_PTR_SUB RTE_INT_PTR_SUB
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
@@ -84,8 +87,8 @@
#define PLT_U16_CAST(val) ((uint16_t)(val))
/* Add / Sub pointer with scalar and cast to uint64_t */
-#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_ADD(__ptr, __x))
-#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_PTR_SUB(__ptr, __x))
+#define PLT_PTR_ADD_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_ADD(__ptr, __x))
+#define PLT_PTR_SUB_U64_CAST(__ptr, __x) PLT_U64_CAST(PLT_INT_PTR_SUB(__ptr, __x))
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..af0b50753d 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 32), aw2);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 48), aw3);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 64), aw4);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 80), aw5);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 96), aw6);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 32), aw2);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..ad369af7f3 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 32), aw2);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 48), aw3);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 64), aw4);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 80), aw5);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 96), aw6);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 32), aw2);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR_ADD(lmt_addr, 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..c4e03f45f7 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1058,6 +1059,7 @@ rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
return NULL;
}
+ RTE_ASSERT(arr->data);
ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
return ret;
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..ee7054ec14 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1607,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1619,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..cd7b143343 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,100 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
+ */
+#define RTE_INT_PTR_ADD(intptr, x) \
+ ((void *)((uintptr_t)(intptr) + (x)))
+
+/**
+ * Subtract a byte-value offset from an integer representing a pointer address.
+ *
+ * @param intptr
+ * Integer representation of a pointer address
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* pointer (result of integer arithmetic cast to pointer)
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#define RTE_INT_PTR_SUB(intptr, x) \
+ ((void *)((uintptr_t)(intptr) - (x)))
/**
- * subtract a byte-value offset from a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
+
+/**
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
+ */
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +726,56 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +787,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +842,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [REVIEW] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
2026-01-25 22:24 ` Scott Mitchell
@ 2026-01-26 8:19 ` Morten Brørup
1 sibling, 0 replies; 60+ messages in thread
From: Morten Brørup @ 2026-01-26 8:19 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: Scott Mitchell
Stephen,
The email subject should reflect which version of the patch the review covers.
PS: Thanks for all the work you are putting into AI review and automating it, Stephen. It's great to follow the progress from experimentation to production. :-)
-Morten
^ permalink raw reply [flat|nested] 60+ messages in thread
* RE: [PATCH v14] eal: RTE_PTR_ADD/SUB API improvements
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
@ 2026-01-26 14:35 ` Morten Brørup
2026-01-26 21:29 ` Scott Mitchell
2026-01-27 5:11 ` Scott Mitchell
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: Morten Brørup @ 2026-01-26 14:35 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
> 1. ptr cast to uintptr_t drops pointer provenance and
> prevents compiler optimizations
> 2. return cast discards qualifiers (const, volatile)
> which may hide correctness/concurrency issues.
> 3. Accepts both "pointers" and "integers as pointers" which
> overloads the use case and constrains the implementation
> to address other challenges.
>
> This patch splits the API on two dimensions:
> 1. pointer types
> 2. integer types that represent pointers
>
> This split allows addressing each of the challenges above
> and provides distinct APIs for the distinct use cases.
First of all, I think it's a huge improvement of the RTE_PTR_ADD/SUB macros to not discard qualifiers anymore.
Silently discarding qualifiers will cause bugs (discarding volatile) and potentially degrade performance (discarding const).
And I agree with your approach of generally fixing instances where this qualifier-discarding property is abused across existing code.
Qualifiers should only be explicitly discarded.
Unfortunately, fixing the macros changes their behavior, which may be considered API breakage.
Personally, I consider the qualifier-discarding property of the current macros a bug, which makes your patch a bug fix.
I would like the opinion of other community members on this!
It seems a patch can be both a bug fix and an API break. ;-)
Second, I think RTE_INT_PTR_ADD/SUB macros are superfluous.
Just use standard + and - operations when operating on integers, including "integers as pointers".
I guess existing instances of RTE_PTR_ADD/SUB operating on "integers as pointers" can be fixed across existing code to either use standard +/- operators or - probably more correct - use actual pointer types instead of integer types.
<feature creep>
If we decide to proceed with the RTE_PTR_ADD/SUB macros not discarding qualifiers, similar RTE_PTR_ macros should be updated similarly.
But let's cross that bridge if we go there.
</feature creep>
-Morten
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v14] eal: RTE_PTR_ADD/SUB API improvements
2026-01-26 14:35 ` Morten Brørup
@ 2026-01-26 21:29 ` Scott Mitchell
2026-01-27 5:11 ` Scott Mitchell
1 sibling, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-26 21:29 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
> First of all, I think it's a huge improvement of the RTE_PTR_ADD/SUB macros to not discard qualifiers anymore.
> Silently discarding qualifiers will cause bugs (discarding volatile) and potentially degrade performance (discarding const).
Yay! It's been an iterative process but I agree it is converging to a
better result.
> And I agree with your approach of generally fixing instances where this qualifier-discarding property is abused across existing code.
> Qualifiers should only be explicitly discarded.
>
> Unfortunately, fixing the macros changes their behavior, which may be considered API breakage.
> Personally, I consider the qualifier-discarding property of the current macros a bug, which makes your patch a bug fix.
> I would like the opinion of other community members on this!
> It seems a patch can be both a bug fix and an API break. ;-)
I agree this is a breaking change for these APIs. Just to clarify that
is OK for inclusion in main (for next LTS) and just debating how/if we
backport, correct? If so, another option is to deprecate the existing
APIs, stop using them in DPDK, and introduce implementations in this
patch as a new API (e.g. RTE_PTR_ADD_TYPED) that is used instead.
> Second, I think RTE_INT_PTR_ADD/SUB macros are superfluous.
> Just use standard + and - operations when operating on integers, including "integers as pointers".
>
> I guess existing instances of RTE_PTR_ADD/SUB operating on "integers as pointers" can be fixed across existing code to either use standard +/- operators or - probably more correct - use actual pointer types instead of integer types.
Good topic. The current RTE_INT_PTR_ADD macros are doing 2 things:
1. Offsetting by an amount
2. Safely converting to void* to prevent bugs where compilers assume
aligned memory, which isn't guaranteed generally, and may crash at
runtime (which I did in my first attempt which preserved pointer
return type).
For (1), agreed for strict integer operation: use native operators
(e.g. + or -). I tried to take that approach in this PR for
clear-cut-cases.
For (2) I think there is still merit in having a macro to convert
between domains safley (e.g. int -> pointer). This macro
implementation would be the same as RTE_PTR_UNQUAL, but I think it's
worth adding an explicit macro bcz the semantics/motivation may be
different (and maybe we find a better way to do the conversion in the
future). I can add RTE_PTR_FROM_INT(..) or similar to see what people
think.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v15 0/2] eal: RTE_PTR_ADD/SUB API improvements
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
2026-01-26 14:35 ` Morten Brørup
@ 2026-01-27 2:02 ` scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
` (2 more replies)
1 sibling, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 2:02 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott
From: Scott <scott.k.mitch1@gmail.com>
This series addresses two issues:
1. Removes the semantically incorrect __rte_alloc_size attribute from
rte_lcore_var_alloc which was causing FORTIFY_SOURCE failures on
Ubuntu 24.04 CI. The attribute was incorrect because the function
returns a handle to per-lcore variables, not a direct pointer to
'size' bytes.
2. Improves RTE_PTR_ADD/SUB macros to preserve pointer type qualifiers
(const/volatile) and use pointer arithmetic instead of integer casts
to enable compiler optimizations and maintain pointer provenance.
The bugfix (patch 1) is placed first so it can be backported independently
to stable branches.
---
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
Scott Mitchell (2):
eal: remove alloc_size from rte_lcore_var_alloc
eal: RTE_PTR_ADD/SUB API improvements
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/include/rte_lcore_var.h | 2 +-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
46 files changed, 648 insertions(+), 135 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
@ 2026-01-27 2:02 ` scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 2:02 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell, mattias.ronnblom,
stable
From: Scott Mitchell <scott.k.mitch1@gmail.com>
The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
semantically incorrect and causes false positives with FORTIFY_SOURCE
runtime checks.
The attribute tells the compiler that the function returns a pointer
to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
actually returns a handle to a per-lcore variable scheme. The
allocator internally allocates 'size' bytes per lcore
(size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
The handle points to lcore 0's copy, and accessed via
RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
but FORTIFY_SOURCE may terminate the program due to out of bounds
access.
This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
'*** buffer overflow detected ***: terminated' if pointer provenance
is preserved (e.g. if offsets avoid casting to uintptr_t).
Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
Cc: mattias.ronnblom@ericsson.com
Cc: stable@dpdk.org
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
lib/eal/include/rte_lcore_var.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/eal/include/rte_lcore_var.h b/lib/eal/include/rte_lcore_var.h
index ca31dff6fd..48b022e84e 100644
--- a/lib/eal/include/rte_lcore_var.h
+++ b/lib/eal/include/rte_lcore_var.h
@@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void *handle)
__rte_experimental
void *
rte_lcore_var_alloc(size_t size, size_t align)
- __rte_alloc_size(1) __rte_alloc_align(2);
+ __rte_alloc_align(2);
#ifdef __cplusplus
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v15 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-01-27 2:02 ` scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 2:02 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
45 files changed, 647 insertions(+), 134 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..7332ff53f4 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(SMALLER + PTR_DIFF), (void *)BIGGER,
+ "RTE_INT_PTR");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(BIGGER - PTR_DIFF), (void *)SMALLER,
+ "RTE_INT_PTR");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..79c6ddf746
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR failed for NULL + offset");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR failed for NULL - offset");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR(ull + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR(ull_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR(ll + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long long");
+ ll_result = (long long)RTE_INT_PTR(ll_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long");
+ ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)(uintptr_t)RTE_INT_PTR(l + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long");
+ l_result = (long)(uintptr_t)RTE_INT_PTR(l_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR(i + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR(i_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR(u64 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR(u64_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR(sz + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR(sz_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ /* Align buffer for uint32_t access to avoid alignment issues */
+ alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..cabec95b37 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,17 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD`` and ``RTE_PTR_SUB`` now preserve const/volatile qualifiers
+ and use pointer arithmetic instead of integer casts to enable compiler optimizations.
+ * Passing NULL to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB`` is now undefined behavior.
+ * Added ``RTE_INT_PTR`` for converting integer addresses to pointers.
+ * Added ``RTE_INT_PTR_ALIGN``, ``RTE_INT_PTR_ALIGN_FLOOR``, and ``RTE_INT_PTR_ALIGN_CEIL``
+ for aligning integer addresses.
+ * Existing code using ``RTE_PTR_ADD``/``RTE_PTR_SUB`` with integer types should migrate
+ to ``RTE_INT_PTR_*`` variants for clarity and correctness.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..4a5baa9a78 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR RTE_INT_PTR
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..c4e03f45f7 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1058,6 +1059,7 @@ rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
return NULL;
}
+ RTE_ASSERT(arr->data);
ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
return ret;
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..ee7054ec14 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1607,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1619,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..1287b30fc9 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -567,11 +665,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for casting pointers ********/
+/**
+ * Convert an integer value to a void pointer.
+ *
+ * Safely converts an integer (typically uintptr_t) to a void pointer,
+ * stripping any alignment assumptions.
+ *
+ * @param val
+ * Integer value to convert (typically uintptr_t)
+ * @return
+ * The value as a void pointer
+ */
+#define RTE_INT_PTR(val) ((void *)(uintptr_t)(val))
+
/**
* Macro to discard qualifiers (such as const, volatile, restrict) from a pointer,
* without the compiler emitting a warning.
*/
-#define RTE_PTR_UNQUAL(X) ((void *)(uintptr_t)(X))
+#define RTE_PTR_UNQUAL(X) RTE_INT_PTR(X)
/**
* Macro to cast a pointer to a specific type,
@@ -602,13 +713,56 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +774,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +829,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v14] eal: RTE_PTR_ADD/SUB API improvements
2026-01-26 14:35 ` Morten Brørup
2026-01-26 21:29 ` Scott Mitchell
@ 2026-01-27 5:11 ` Scott Mitchell
1 sibling, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-01-27 5:11 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
> <feature creep>
> If we decide to proceed with the RTE_PTR_ADD/SUB macros not discarding qualifiers, similar RTE_PTR_ macros should be updated similarly.
> But let's cross that bridge if we go there.
> </feature creep>
Is RTE_PTR_DIFF the only remaining? There is no difference in assembly
by casting to uintptr_t https://godbolt.org/z/z77nEr6Ts (I assume bcz
integer return means pointer provenance isn't broken). Native pointer
types will throw an error if the pointers are not of the same type
which can strengthen type checking, but similar call-site analysis
will be needed as there is mixed usage (different ptr types, int + ptr
types).
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v16 0/2] eal: RTE_PTR_ADD/SUB API improvements
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-01-27 5:28 ` scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
` (2 more replies)
2 siblings, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 5:28 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott
From: Scott <scott.k.mitch1@gmail.com>
This series addresses two issues:
1. Removes the semantically incorrect __rte_alloc_size attribute from
rte_lcore_var_alloc which was causing FORTIFY_SOURCE failures on
Ubuntu 24.04 CI. The attribute was incorrect because the function
returns a handle to per-lcore variables, not a direct pointer to
'size' bytes.
2. Improves RTE_PTR_ADD/SUB macros to preserve pointer type qualifiers
(const/volatile) and use pointer arithmetic instead of integer casts
to enable compiler optimizations and maintain pointer provenance.
The bugfix (patch 1) is placed first so it can be backported independently
to stable branches.
---
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
Scott Mitchell (2):
eal: remove alloc_size from rte_lcore_var_alloc
eal: RTE_PTR_ADD/SUB API improvements
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/include/rte_lcore_var.h | 2 +-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
46 files changed, 648 insertions(+), 135 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
@ 2026-01-27 5:28 ` scott.k.mitch1
2026-01-27 11:16 ` Mattias Rönnblom
2026-01-27 14:07 ` Stephen Hemminger
2026-01-27 5:29 ` [PATCH v16 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 5:28 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell, mattias.ronnblom,
stable
From: Scott Mitchell <scott.k.mitch1@gmail.com>
The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
semantically incorrect and causes false positives with FORTIFY_SOURCE
runtime checks.
The attribute tells the compiler that the function returns a pointer
to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
actually returns a handle to a per-lcore variable scheme. The
allocator internally allocates 'size' bytes per lcore
(size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
The handle points to lcore 0's copy, and accessed via
RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
but FORTIFY_SOURCE may terminate the program due to out of bounds
access.
This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
'*** buffer overflow detected ***: terminated' if pointer provenance
is preserved (e.g. if offsets avoid casting to uintptr_t).
Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
Cc: mattias.ronnblom@ericsson.com
Cc: stable@dpdk.org
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
lib/eal/include/rte_lcore_var.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/eal/include/rte_lcore_var.h b/lib/eal/include/rte_lcore_var.h
index ca31dff6fd..48b022e84e 100644
--- a/lib/eal/include/rte_lcore_var.h
+++ b/lib/eal/include/rte_lcore_var.h
@@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void *handle)
__rte_experimental
void *
rte_lcore_var_alloc(size_t size, size_t align)
- __rte_alloc_size(1) __rte_alloc_align(2);
+ __rte_alloc_align(2);
#ifdef __cplusplus
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v16 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-01-27 5:29 ` scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-01-27 5:29 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 11 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 2 +
lib/eal/common/eal_common_memory.c | 31 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
45 files changed, 647 insertions(+), 134 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..a2507d0f51 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(SMALLER + (PTR_DIFF)), (void *)BIGGER,
+ "RTE_INT_PTR ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(BIGGER - (PTR_DIFF)), (void *)SMALLER,
+ "RTE_INT_PTR SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..79c6ddf746
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR failed for NULL + offset");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR failed for NULL - offset");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR(ull + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR(ull_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR(ll + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long long");
+ ll_result = (long long)RTE_INT_PTR(ll_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long");
+ ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)(uintptr_t)RTE_INT_PTR(l + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long");
+ l_result = (long)(uintptr_t)RTE_INT_PTR(l_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR(i + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR(i_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR(u64 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR(u64_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR(sz + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR(sz_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ /* Align buffer for uint32_t access to avoid alignment issues */
+ alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..cabec95b37 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,17 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD`` and ``RTE_PTR_SUB`` now preserve const/volatile qualifiers
+ and use pointer arithmetic instead of integer casts to enable compiler optimizations.
+ * Passing NULL to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB`` is now undefined behavior.
+ * Added ``RTE_INT_PTR`` for converting integer addresses to pointers.
+ * Added ``RTE_INT_PTR_ALIGN``, ``RTE_INT_PTR_ALIGN_FLOOR``, and ``RTE_INT_PTR_ALIGN_CEIL``
+ for aligning integer addresses.
+ * Existing code using ``RTE_PTR_ADD``/``RTE_PTR_SUB`` with integer types should migrate
+ to ``RTE_INT_PTR_*`` variants for clarity and correctness.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..4a5baa9a78 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR RTE_INT_PTR
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..c4e03f45f7 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1058,6 +1059,7 @@ rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
return NULL;
}
+ RTE_ASSERT(arr->data);
ret = RTE_PTR_ADD(arr->data, idx * arr->elt_sz);
return ret;
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..ee7054ec14 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1607,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1619,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..1287b30fc9 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -567,11 +665,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for casting pointers ********/
+/**
+ * Convert an integer value to a void pointer.
+ *
+ * Safely converts an integer (typically uintptr_t) to a void pointer,
+ * stripping any alignment assumptions.
+ *
+ * @param val
+ * Integer value to convert (typically uintptr_t)
+ * @return
+ * The value as a void pointer
+ */
+#define RTE_INT_PTR(val) ((void *)(uintptr_t)(val))
+
/**
* Macro to discard qualifiers (such as const, volatile, restrict) from a pointer,
* without the compiler emitting a warning.
*/
-#define RTE_PTR_UNQUAL(X) ((void *)(uintptr_t)(X))
+#define RTE_PTR_UNQUAL(X) RTE_INT_PTR(X)
/**
* Macro to cast a pointer to a specific type,
@@ -602,13 +713,56 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +774,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +829,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-01-27 11:16 ` Mattias Rönnblom
2026-01-27 14:07 ` Stephen Hemminger
1 sibling, 0 replies; 60+ messages in thread
From: Mattias Rönnblom @ 2026-01-27 11:16 UTC (permalink / raw)
To: scott.k.mitch1, dev
Cc: mb, stephen, bruce.richardson, mattias.ronnblom, stable
On 1/27/26 06:28, scott.k.mitch1@gmail.com wrote:
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
> semantically incorrect and causes false positives with FORTIFY_SOURCE
> runtime checks.
>
> The attribute tells the compiler that the function returns a pointer
> to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
> actually returns a handle to a per-lcore variable scheme. The
> allocator internally allocates 'size' bytes per lcore
> (size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
> The handle points to lcore 0's copy, and accessed via
> RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
> handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
> beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
> but FORTIFY_SOURCE may terminate the program due to out of bounds
> access.
>
> This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
> '*** buffer overflow detected ***: terminated' if pointer provenance
> is preserved (e.g. if offsets avoid casting to uintptr_t).
>
> Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
> Cc: mattias.ronnblom@ericsson.com
> Cc: stable@dpdk.org
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
> ---
Acked-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>
Thanks!
> lib/eal/include/rte_lcore_var.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/eal/include/rte_lcore_var.h b/lib/eal/include/rte_lcore_var.h
> index ca31dff6fd..48b022e84e 100644
> --- a/lib/eal/include/rte_lcore_var.h
> +++ b/lib/eal/include/rte_lcore_var.h
> @@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void *handle)
> __rte_experimental
> void *
> rte_lcore_var_alloc(size_t size, size_t align)
> - __rte_alloc_size(1) __rte_alloc_align(2);
> + __rte_alloc_align(2);
>
> #ifdef __cplusplus
> }
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 11:16 ` Mattias Rönnblom
@ 2026-01-27 14:07 ` Stephen Hemminger
1 sibling, 0 replies; 60+ messages in thread
From: Stephen Hemminger @ 2026-01-27 14:07 UTC (permalink / raw)
To: scott.k.mitch1; +Cc: dev, mb, bruce.richardson, mattias.ronnblom, stable
On Mon, 26 Jan 2026 21:28:59 -0800
scott.k.mitch1@gmail.com wrote:
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
> semantically incorrect and causes false positives with FORTIFY_SOURCE
> runtime checks.
>
> The attribute tells the compiler that the function returns a pointer
> to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
> actually returns a handle to a per-lcore variable scheme. The
> allocator internally allocates 'size' bytes per lcore
> (size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
> The handle points to lcore 0's copy, and accessed via
> RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
> handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
> beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
> but FORTIFY_SOURCE may terminate the program due to out of bounds
> access.
>
> This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
> '*** buffer overflow detected ***: terminated' if pointer provenance
> is preserved (e.g. if offsets avoid casting to uintptr_t).
>
> Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
> Cc: mattias.ronnblom@ericsson.com
> Cc: stable@dpdk.org
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
^ permalink raw reply [flat|nested] 60+ messages in thread
* [REVIEW] eal: RTE_PTR_ADD/SUB API improvements
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
@ 2026-01-27 20:28 ` Stephen Hemminger
2026-02-02 5:17 ` Scott Mitchell
1 sibling, 1 reply; 60+ messages in thread
From: Stephen Hemminger @ 2026-01-27 20:28 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
AI-generated review of ptr-add.mbox
Reviewed using Claude (claude-opus-4-5-20251101)
This is an automated review. Please verify all suggestions.
---
## DPDK Patch Review: `[PATCH v13] eal: RTE_PTR_ADD/SUB API improvements`
### Summary
This patch refactors the `RTE_PTR_ADD` and `RTE_PTR_SUB` macros to preserve pointer provenance and type qualifiers, adds new `RTE_INT_PTR_*` variants for integer-as-pointer arithmetic, and updates all callers across the codebase.
---
### Errors
1. **Subject line exceeds 60 characters**
- Current: `eal: RTE_PTR_ADD/SUB API improvements` (39 chars) - Actually OK
- No error here.
2. **Missing `Cc: stable@dpdk.org`**
- This patch changes API behavior (NULL to `RTE_PTR_ADD`/`RTE_PTR_SUB` is now undefined). If this is considered a fix for existing issues, it should include `Cc: stable@dpdk.org`.
3. **Commit body starts with "RTE_PTR_ADD"**
- The body should provide context before diving into technical details. Consider starting with "The" or describing the problem first.
---
### Warnings
1. **Implicit comparison with NULL in several places**
```c
// drivers/bus/cdx/cdx_vfio.c:374
if (msl->base_va == NULL)
```
This is correct style. Good.
2. **`__rte_auto_type` documentation could be clearer**
- Line ~108 in `rte_common.h`: The comment should clarify this is a DPDK internal macro, not for general use.
3. **Missing explicit NULL checks before some `RTE_PTR_ADD` calls**
- `lib/eal/common/eal_common_fbarray.c:1062`: Added `RTE_ASSERT(arr->data)` - good, but this is a debug-only check. Consider returning error in release builds.
4. **Diagnostic pragma usage in `malloc_elem.h`**
```c
__rte_diagnostic_push
__rte_diagnostic_ignored_array_bounds
struct malloc_elem *elem = RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
...
return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB(elem, elem->pad);
__rte_diagnostic_pop
```
The `__rte_diagnostic_pop` should be on its own statement or the return should be before it. As written, the pop is unreachable after return.
5. **`volatile` qualifier handling in `idxd_pci.c`**
```c
// Line 62
static volatile uint32_t *
idxd_get_wq_cfg(struct idxd_pci_common *pci, uint8_t wq_idx)
```
Good fix, but the FIXME comment at line 398-400 indicates incomplete resolution:
```c
/* FIXME: cast drops volatile propagation to idxd_dmadev.portal
* See: https://bugs.dpdk.org/show_bug.cgi?id=1871
*/
idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
```
This should be tracked in the commit message or release notes.
6. **`RTE_PTR_UNQUAL` macro is used but not defined in this patch**
- The patch uses `RTE_PTR_UNQUAL` in multiple places but the macro definition is not visible in the diff. Ensure it exists or is added.
7. **Test file uses `alignas` from `<stdalign.h>`**
```c
#include <stdalign.h>
...
alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
```
This is C11 but DPDK targets C11, so acceptable. However, verify MSVC compatibility.
8. **`drivers/dma/odm/odm_dmadev.c` changes remove `const`**
```c
// Before: const uint32_t *base_addr = vq->cring_mz->addr;
// After: uint32_t *base_addr = vq->cring_mz->addr;
```
This removes a useful const qualifier. If the intent is to allow writes, document why. If not, preserve const.
9. **Release notes format**
- The API Changes section uses bullet points correctly but should reference the specific macros more prominently for searchability.
---
### Info
1. **Good practices observed:**
- Proper use of `unit_test_suite_runner` in test file
- `TEST_ASSERT` macros used correctly
- Release notes included for API changes
- NULL checks added where `RTE_PTR_ADD` is used with potentially NULL pointers
- Comprehensive test coverage for both pointer and integer types
2. **Code organization in `rte_common.h`:**
- The new macros are well-documented with Doxygen comments
- The `__rte_auto_type` abstraction is clean for cross-compiler support
3. **Changelog in commit message:**
- Detailed version history (v1-v13) is helpful for reviewers
4. **Consider adding to documentation:**
- The behavioral change (NULL is now undefined for `RTE_PTR_ADD`/`RTE_PTR_SUB`) should be prominently noted in the programmer's guide, not just release notes.
---
### Specific Code Issues
**`lib/eal/common/malloc_elem.h:312-322`:**
```c
__rte_diagnostic_push
__rte_diagnostic_ignored_array_bounds
struct malloc_elem *elem = RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
if (!malloc_elem_cookies_ok(elem))
return NULL;
return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB(elem, elem->pad);
__rte_diagnostic_pop
```
The `__rte_diagnostic_pop` is placed after return statements and will never execute. Move the pop before the final return or restructure:
```c
__rte_diagnostic_push
__rte_diagnostic_ignored_array_bounds
struct malloc_elem *elem = RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
__rte_diagnostic_pop
if (!malloc_elem_cookies_ok(elem))
return NULL;
return elem->state != ELEM_PAD ? elem : RTE_PTR_SUB(elem, elem->pad);
```
**`lib/eal/common/eal_common_memory.c:1563`:**
```c
struct malloc_elem *volatile elem;
```
The `volatile` on a local pointer variable is unusual. This appears to be preventing optimization, but the rationale should be documented.
---
### Verdict
This is a well-structured patch with good documentation and test coverage. The main issues are:
1. The diagnostic pragma placement bug in `malloc_elem.h`
2. Missing definition of `RTE_PTR_UNQUAL` in the visible diff
3. The ODM driver const removal needs justification
Recommend addressing the pragma placement issue before merge.
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [REVIEW] eal: RTE_PTR_ADD/SUB API improvements
2026-01-27 20:28 ` [REVIEW] " Stephen Hemminger
@ 2026-02-02 5:17 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-02 5:17 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev
> 2. **Missing `Cc: stable@dpdk.org`**
> - This patch changes API behavior (NULL to `RTE_PTR_ADD`/`RTE_PTR_SUB` is now undefined). If this is considered a fix for existing issues, it should include `Cc: stable@dpdk.org`.
Morten opened a discussion on this. It's API breaking so I'm not
proposing backporting. If backporting is desired and API compatibility
is required an option is to deprecate existing macros, and introduce
new implementation with a distinct naming convention (e.g.
RTE_PTR_QUAL_ALL - qualified add), then remove old macros in the main
branch.
> 3. **Missing explicit NULL checks before some `RTE_PTR_ADD` calls**
> - `lib/eal/common/eal_common_fbarray.c:1062`: Added `RTE_ASSERT(arr->data)` - good, but this is a debug-only check. Consider returning error in release builds.
I'll add a runtime check here. Note there are other cases where APIs
didn't have any null handling and would have crashed, and I added an
assert to at least be explicit about expectations.
> 5. **`volatile` qualifier handling in `idxd_pci.c`**
> ```c
> // Line 62
> static volatile uint32_t *
> idxd_get_wq_cfg(struct idxd_pci_common *pci, uint8_t wq_idx)
> ```
> Good fix, but the FIXME comment at line 398-400 indicates incomplete resolution:
> ```c
> /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
> * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
> */
> idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
> ```
> This should be tracked in the commit message or release notes.
Can you clarify what would be captured in this commit message or
release notes? This commit isn't introducing any issues, and a bug was
filed to follow up.
>
> 6. **`RTE_PTR_UNQUAL` macro is used but not defined in this patch**
> - The patch uses `RTE_PTR_UNQUAL` in multiple places but the macro definition is not visible in the diff. Ensure it exists or is added.
False positive.
>
> 8. **`drivers/dma/odm/odm_dmadev.c` changes remove `const`**
> ```c
> // Before: const uint32_t *base_addr = vq->cring_mz->addr;
> // After: uint32_t *base_addr = vq->cring_mz->addr;
> ```
> This removes a useful const qualifier. If the intent is to allow writes, document why. If not, preserve const.
The comment would be similar to "this value is used in a non-const
way, so don't use const", and I don't think this adds too much value.
>
> 9. **Release notes format**
> - The API Changes section uses bullet points correctly but should reference the specific macros more prominently for searchability.
Clarified.
>
> **`lib/eal/common/eal_common_memory.c:1563`:**
> ```c
> struct malloc_elem *volatile elem;
> ```
> The `volatile` on a local pointer variable is unusual. This appears to be preventing optimization, but the rationale should be documented.
Comment added.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v17 0/2] eal: RTE_PTR_ADD/SUB API improvements
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 5:29 ` [PATCH v16 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-02-02 5:24 ` scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
` (2 more replies)
2 siblings, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-02 5:24 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott
From: Scott <scott.k.mitch1@gmail.com>
This series addresses two issues:
1. Removes the semantically incorrect __rte_alloc_size attribute from
rte_lcore_var_alloc which was causing FORTIFY_SOURCE failures on
Ubuntu 24.04 CI. The attribute was incorrect because the function
returns a handle to per-lcore variables, not a direct pointer to
'size' bytes.
2. Improves RTE_PTR_ADD/SUB macros to preserve pointer type qualifiers
(const/volatile) and use pointer arithmetic instead of integer casts
to enable compiler optimizations and maintain pointer provenance.
The bugfix (patch 1) is placed first so it can be backported independently
to stable branches.
---
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
Scott Mitchell (2):
eal: remove alloc_size from rte_lcore_var_alloc
eal: RTE_PTR_ADD/SUB API improvements
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 14 ++
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/include/rte_lcore_var.h | 2 +-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
46 files changed, 652 insertions(+), 136 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
@ 2026-02-02 5:24 ` scott.k.mitch1
2026-02-03 8:24 ` Morten Brørup
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2 siblings, 1 reply; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-02 5:24 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell, mattias.ronnblom,
stable
From: Scott Mitchell <scott.k.mitch1@gmail.com>
The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
semantically incorrect and causes false positives with FORTIFY_SOURCE
runtime checks.
The attribute tells the compiler that the function returns a pointer
to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
actually returns a handle to a per-lcore variable scheme. The
allocator internally allocates 'size' bytes per lcore
(size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
The handle points to lcore 0's copy, and accessed via
RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
but FORTIFY_SOURCE may terminate the program due to out of bounds
access.
This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
'*** buffer overflow detected ***: terminated' if pointer provenance
is preserved (e.g. if offsets avoid casting to uintptr_t).
Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
Cc: mattias.ronnblom@ericsson.com
Cc: stable@dpdk.org
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
lib/eal/include/rte_lcore_var.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/eal/include/rte_lcore_var.h b/lib/eal/include/rte_lcore_var.h
index ca31dff6fd..48b022e84e 100644
--- a/lib/eal/include/rte_lcore_var.h
+++ b/lib/eal/include/rte_lcore_var.h
@@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void *handle)
__rte_experimental
void *
rte_lcore_var_alloc(size_t size, size_t align)
- __rte_alloc_size(1) __rte_alloc_align(2);
+ __rte_alloc_align(2);
#ifdef __cplusplus
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-02-02 5:24 ` scott.k.mitch1
2026-02-03 9:08 ` Morten Brørup
2026-02-03 9:51 ` David Marchand
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-02 5:24 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
app/test-pmd/cmdline_flow.c | 4 +-
app/test/meson.build | 1 +
app/test/test_common.c | 20 +-
app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
doc/guides/rel_notes/release_26_03.rst | 14 ++
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +--
drivers/event/cnxk/cn20k_worker.c | 32 +--
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 ++-
lib/eal/common/eal_common_options.c | 2 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 231 ++++++++++++++++++--
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
45 files changed, 651 insertions(+), 135 deletions(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/meson.build b/app/test/meson.build
index f4d04a6e42..aa56fc4297 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..a2507d0f51 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -37,10 +37,10 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(SMALLER + (PTR_DIFF)), (void *)BIGGER,
+ "RTE_INT_PTR ADD");
+ RTE_TEST_ASSERT_EQUAL(RTE_INT_PTR(BIGGER - (PTR_DIFF)), (void *)SMALLER,
+ "RTE_INT_PTR SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,18 +188,18 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_FLOOR((uintptr_t) i, p);
if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_FLOOR", i, p);
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN((uintptr_t) i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN", i, p);
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
@@ -209,9 +209,9 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
+ val = (uint32_t)(uintptr_t)RTE_INT_PTR_ALIGN_CEIL((uintptr_t)i, p);
if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
+ FAIL_ALIGN("RTE_INT_PTR_ALIGN_CEIL", i, p);
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..79c6ddf746
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test RTE_INT_PTR with integer types and NULL */
+static int
+test_int_ptr_add_sub(void)
+{
+ /* Test NULL + offset */
+ uintptr_t uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)TEST_INCREMENT,
+ "RTE_INT_PTR failed for NULL + offset");
+
+ uptr_result = (uintptr_t)RTE_INT_PTR((uintptr_t)NULL - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(-TEST_INCREMENT),
+ "RTE_INT_PTR failed for NULL - offset");
+
+ /* Test with various integer types that could represent pointers */
+ unsigned long long ull = TEST_INITVAL;
+ unsigned long long ull_result = (unsigned long long)RTE_INT_PTR(ull + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, (unsigned long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long long");
+ ull_result = (unsigned long long)RTE_INT_PTR(ull_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ull_result, ull,
+ "RTE_INT_PTR round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ long long ll_result = (long long)RTE_INT_PTR(ll + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, (long long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long long");
+ ll_result = (long long)RTE_INT_PTR(ll_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ll_result, ll,
+ "RTE_INT_PTR round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ unsigned long ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, (unsigned long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned long");
+ ul_result = (unsigned long)(uintptr_t)RTE_INT_PTR(ul_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ul_result, ul,
+ "RTE_INT_PTR round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ long l_result = (long)(uintptr_t)RTE_INT_PTR(l + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, (long)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for long");
+ l_result = (long)(uintptr_t)RTE_INT_PTR(l_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(l_result, l,
+ "RTE_INT_PTR round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ unsigned int ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, (unsigned int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for unsigned int");
+ ui_result = (unsigned int)(uintptr_t)RTE_INT_PTR(ui_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ui_result, ui,
+ "RTE_INT_PTR round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ int i_result = (int)(uintptr_t)RTE_INT_PTR(i + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, (int)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for int");
+ i_result = (int)(uintptr_t)RTE_INT_PTR(i_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(i_result, i,
+ "RTE_INT_PTR round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ uint64_t u64_result = (uint64_t)RTE_INT_PTR(u64 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, (uint64_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint64_t");
+ u64_result = (uint64_t)RTE_INT_PTR(u64_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u64_result, u64,
+ "RTE_INT_PTR round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ uint32_t u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32 + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, (uint32_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uint32_t");
+ u32_result = (uint32_t)(uintptr_t)RTE_INT_PTR(u32_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32_result, u32,
+ "RTE_INT_PTR round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, (uintptr_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for uintptr_t");
+ uptr_result = (uintptr_t)RTE_INT_PTR(uptr - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(uptr_result, uptr - TEST_INCREMENT,
+ "RTE_INT_PTR failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ size_t sz_result = (size_t)RTE_INT_PTR(sz + TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, (size_t)(TEST_INITVAL + TEST_INCREMENT),
+ "RTE_INT_PTR failed for size_t");
+ sz_result = (size_t)RTE_INT_PTR(sz_result - TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(sz_result, sz,
+ "RTE_INT_PTR round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test RTE_PTR_ADD/SUB with pointer types and type preservation */
+static int
+test_ptr_add_sub(void)
+{
+ /* Align buffer for uint32_t access to avoid alignment issues */
+ alignas(uint32_t) char buffer[TEST_BUFFER_SIZE];
+
+ /* Test void* */
+ void *vp = buffer;
+ void *result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ /* Test const void* - verifies const preservation */
+ const void *cvp = buffer;
+ const void *cvp_result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ cvp_result = RTE_PTR_SUB(cvp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cvp_result, cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* - verifies type preservation */
+ char *cp = buffer;
+ char *cp_result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for char*");
+ cp_result = RTE_PTR_SUB(cp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cp_result, cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ /* Test const char* - verifies type and const preservation */
+ const char *ccp = buffer;
+ const char *ccp_result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, buffer + TEST_INCREMENT,
+ "RTE_PTR_ADD failed for const char*");
+ ccp_result = RTE_PTR_SUB(ccp_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(ccp_result, ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* - verifies typed pointer preservation */
+ uint32_t *u32p = (uint32_t *)buffer;
+ uint32_t *u32p_result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, (uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ u32p_result = RTE_PTR_SUB(u32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(u32p_result, u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ /* Test const uint32_t* - verifies typed pointer and const preservation */
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ const uint32_t *cu32p_result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, (const uint32_t *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ cu32p_result = RTE_PTR_SUB(cu32p_result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(cu32p_result, cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ return 0;
+}
+
+static struct unit_test_suite ptr_add_sub_test_suite = {
+ .suite_name = "ptr add/sub autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_int_ptr_add_sub),
+ TEST_CASE(test_ptr_add_sub),
+ TEST_CASES_END()
+ }
+};
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub_suite(void)
+{
+ return unit_test_suite_runner(&ptr_add_sub_test_suite);
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub_suite);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..d2157e8b42 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,20 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN_CEIL``, and ``RTE_PTR_ALIGN_FLOOR``
+ now preserve const/volatile qualifiers and use pointer arithmetic instead of integer
+ casts to enable compiler optimizations.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN_CEIL``, or
+ ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Added ``RTE_INT_PTR`` for converting integer addresses to pointers.
+ * Added ``RTE_INT_PTR_ALIGN``, ``RTE_INT_PTR_ALIGN_FLOOR``, and ``RTE_INT_PTR_ALIGN_CEIL``
+ for aligning integer addresses.
+ * Existing code using ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN_CEIL``, or
+ ``RTE_PTR_ALIGN_FLOOR`` with integer types should migrate to ``RTE_INT_PTR*``
+ variants for clarity and correctness.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..4a5baa9a78 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR RTE_INT_PTR
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..5f3168a286 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1608,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1620,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..0e05683a67 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1656,7 +1656,7 @@ eal_parse_base_virtaddr(const char *arg)
* on x86 and other architectures.
*/
internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ (uintptr_t) RTE_INT_PTR_ALIGN_CEIL(addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..1287b30fc9 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -567,11 +665,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for casting pointers ********/
+/**
+ * Convert an integer value to a void pointer.
+ *
+ * Safely converts an integer (typically uintptr_t) to a void pointer,
+ * stripping any alignment assumptions.
+ *
+ * @param val
+ * Integer value to convert (typically uintptr_t)
+ * @return
+ * The value as a void pointer
+ */
+#define RTE_INT_PTR(val) ((void *)(uintptr_t)(val))
+
/**
* Macro to discard qualifiers (such as const, volatile, restrict) from a pointer,
* without the compiler emitting a warning.
*/
-#define RTE_PTR_UNQUAL(X) ((void *)(uintptr_t)(X))
+#define RTE_PTR_UNQUAL(X) RTE_INT_PTR(X)
/**
* Macro to cast a pointer to a specific type,
@@ -602,13 +713,56 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
+
+/**
+ * Align an integer address down to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no higher than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_FLOOR.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_FLOOR(intptr, align) \
+ ((void *)RTE_ALIGN_FLOOR((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +774,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+
+/**
+ * Align an integer address up to a given power-of-two.
+ * Returns void* pointer suitable for dereferencing.
+ *
+ * The resultant address will be no lower than the first parameter.
+ * Second parameter must be a power-of-two value.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN_CEIL.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN_CEIL(intptr, align) \
+ ((void *)RTE_ALIGN_CEIL((uintptr_t)(intptr), align))
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -646,6 +829,24 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
*/
#define RTE_PTR_ALIGN(ptr, align) RTE_PTR_ALIGN_CEIL(ptr, align)
+/**
+ * Align an integer address to a given power-of-two (rounds up).
+ * Returns void* pointer suitable for dereferencing.
+ * This is an alias for RTE_INT_PTR_ALIGN_CEIL.
+ *
+ * Use this when working with numeric addresses (e.g., uintptr_t, uint64_t),
+ * not actual pointer variables. For pointers, use RTE_PTR_ALIGN.
+ *
+ * @param intptr
+ * Integer representation of an address
+ * @param align
+ * Power-of-two alignment value
+ * @return
+ * void* pointer (aligned address cast from integer)
+ */
+#define RTE_INT_PTR_ALIGN(intptr, align) \
+ RTE_INT_PTR_ALIGN_CEIL(intptr, align)
+
/**
* Macro to align a value to a given power-of-two. The resultant
* value will be of the same type as the first parameter, and
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..3100feb740 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..091976574a 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
+ RTE_ASSERT(elt);
const struct rte_mempool_objhdr *hdr;
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-02-03 8:24 ` Morten Brørup
2026-02-03 9:48 ` David Marchand
0 siblings, 1 reply; 60+ messages in thread
From: Morten Brørup @ 2026-02-03 8:24 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson, mattias.ronnblom, stable
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
> semantically incorrect and causes false positives with FORTIFY_SOURCE
> runtime checks.
>
> The attribute tells the compiler that the function returns a pointer
> to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
> actually returns a handle to a per-lcore variable scheme. The
> allocator internally allocates 'size' bytes per lcore
> (size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
> The handle points to lcore 0's copy, and accessed via
> RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
> handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
> beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
> but FORTIFY_SOURCE may terminate the program due to out of bounds
> access.
>
> This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
> '*** buffer overflow detected ***: terminated' if pointer provenance
> is preserved (e.g. if offsets avoid casting to uintptr_t).
>
> Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation
> facility")
> Cc: mattias.ronnblom@ericsson.com
> Cc: stable@dpdk.org
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
> ---
> lib/eal/include/rte_lcore_var.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/eal/include/rte_lcore_var.h
> b/lib/eal/include/rte_lcore_var.h
> index ca31dff6fd..48b022e84e 100644
> --- a/lib/eal/include/rte_lcore_var.h
> +++ b/lib/eal/include/rte_lcore_var.h
> @@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void
> *handle)
> __rte_experimental
> void *
> rte_lcore_var_alloc(size_t size, size_t align)
> - __rte_alloc_size(1) __rte_alloc_align(2);
> + __rte_alloc_align(2);
>
> #ifdef __cplusplus
> }
> --
> 2.39.5 (Apple Git-154)
This patch could be separated from the RTE_PTR_ADD/SUB series.
Acked-by: Morten Brørup <mb@smartsharesystems.com>
NB: Please keep this ACK for any new versions of this patch if the essence of the patch doesn't change.
^ permalink raw reply [flat|nested] 60+ messages in thread
* RE: [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-02-03 9:08 ` Morten Brørup
2026-02-03 16:24 ` Scott Mitchell
2026-02-03 9:51 ` David Marchand
1 sibling, 1 reply; 60+ messages in thread
From: Morten Brørup @ 2026-02-03 9:08 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
> RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
> 1. ptr cast to uintptr_t drops pointer provenance and
> prevents compiler optimizations
> 2. return cast discards qualifiers (const, volatile)
> which may hide correctness/concurrency issues.
> 3. Accepts both "pointers" and "integers as pointers" which
> overloads the use case and constrains the implementation
> to address other challenges.
>
> This patch splits the API on two dimensions:
> 1. pointer types
Again, thank you for all the work you put into this, Scott!
> 2. integer types that represent pointers
Please get rid of all the RTE_INT_PTR macros.
IMO, these macros look too much like plain wrappers around simple +/- operators.
It seems they are only needed for the cnxk drivers; those drivers can probably be fixed in some other way.
>
> This split allows addressing each of the challenges above
> and provides distinct APIs for the distinct use cases.
> Examples:
> 1. Clang is able to optimize and improve __rte_raw_cksum
> (which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
> TSC cycles/byte.
> 2. Refactoring discovered cases that dropped qualifiers (volatile)
> that the new API exposes.
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
> ---
A few minor details follow.
> static inline struct rte_mbuf *
> rte_mbuf_from_indirect(struct rte_mbuf *mi)
> {
> + RTE_ASSERT(mi);
Preferred: RTE_ASSERT(mi != NULL);
> return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) +
> mi->priv_size);
> }
>
> @@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
> static inline void *
> rte_mbuf_to_priv(struct rte_mbuf *m)
> {
> + RTE_ASSERT(m);
Preferred: RTE_ASSERT(m != NULL);
> return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
> }
>
> --- a/lib/mempool/rte_mempool.h
> +++ b/lib/mempool/rte_mempool.h
> @@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
> static inline struct rte_mempool_objhdr *
> rte_mempool_get_header(void *obj)
> {
> + RTE_ASSERT(obj);
Preferred: RTE_ASSERT(obj != NULL);
> return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
> sizeof(struct rte_mempool_objhdr));
> }
> @@ -399,6 +400,7 @@ static inline struct rte_mempool
> *rte_mempool_from_obj(void *obj)
> static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void
> *obj)
> {
> struct rte_mempool *mp = rte_mempool_from_obj(obj);
> + RTE_ASSERT(mp);
Preferred: RTE_ASSERT(mp != NULL);
> return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp-
> >elt_size);
> }
>
> @@ -1844,6 +1846,7 @@ rte_mempool_empty(const struct rte_mempool *mp)
> static inline rte_iova_t
> rte_mempool_virt2iova(const void *elt)
> {
> + RTE_ASSERT(elt);
> const struct rte_mempool_objhdr *hdr;
Preferred: RTE_ASSERT(elt != NULL);
Also, it might be preferable adding the RTE_ASSERT() here instead of above.
> hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
> sizeof(*hdr));
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-02-03 8:24 ` Morten Brørup
@ 2026-02-03 9:48 ` David Marchand
0 siblings, 0 replies; 60+ messages in thread
From: David Marchand @ 2026-02-03 9:48 UTC (permalink / raw)
To: scott.k.mitch1
Cc: dev, Morten Brørup, stephen, bruce.richardson,
mattias.ronnblom, stable
On Tue, 3 Feb 2026 at 09:24, Morten Brørup <mb@smartsharesystems.com> wrote:
>
> > From: Scott Mitchell <scott.k.mitch1@gmail.com>
> >
> > The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
> > semantically incorrect and causes false positives with FORTIFY_SOURCE
> > runtime checks.
> >
> > The attribute tells the compiler that the function returns a pointer
> > to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
> > actually returns a handle to a per-lcore variable scheme. The
> > allocator internally allocates 'size' bytes per lcore
> > (size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
> > The handle points to lcore 0's copy, and accessed via
> > RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
> > handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
> > beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
> > but FORTIFY_SOURCE may terminate the program due to out of bounds
> > access.
> >
> > This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
> > '*** buffer overflow detected ***: terminated' if pointer provenance
> > is preserved (e.g. if offsets avoid casting to uintptr_t).
> >
> > Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation
> > facility")
> > Cc: mattias.ronnblom@ericsson.com
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> This patch could be separated from the RTE_PTR_ADD/SUB series.
I agree.
There were comments on patch 2, so I took this patch directly.
> Acked-by: Morten Brørup <mb@smartsharesystems.com>
>
> NB: Please keep this ACK for any new versions of this patch if the essence of the patch doesn't change.
Yes please, I restored acks from Mattias and Stephen.
Applied, thanks.
--
David Marchand
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-03 9:08 ` Morten Brørup
@ 2026-02-03 9:51 ` David Marchand
2026-02-03 16:25 ` Scott Mitchell
1 sibling, 1 reply; 60+ messages in thread
From: David Marchand @ 2026-02-03 9:51 UTC (permalink / raw)
To: scott.k.mitch1; +Cc: dev, mb, stephen, bruce.richardson
On Mon, 2 Feb 2026 at 06:25, <scott.k.mitch1@gmail.com> wrote:
>
> From: Scott Mitchell <scott.k.mitch1@gmail.com>
>
> RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
> 1. ptr cast to uintptr_t drops pointer provenance and
> prevents compiler optimizations
> 2. return cast discards qualifiers (const, volatile)
> which may hide correctness/concurrency issues.
> 3. Accepts both "pointers" and "integers as pointers" which
> overloads the use case and constrains the implementation
> to address other challenges.
>
> This patch splits the API on two dimensions:
> 1. pointer types
> 2. integer types that represent pointers
>
> This split allows addressing each of the challenges above
> and provides distinct APIs for the distinct use cases.
> Examples:
> 1. Clang is able to optimize and improve __rte_raw_cksum
> (which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
> TSC cycles/byte.
> 2. Refactoring discovered cases that dropped qualifiers (volatile)
> that the new API exposes.
>
> Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
> ---
> app/test-pmd/cmdline_flow.c | 4 +-
> app/test/meson.build | 1 +
> app/test/test_common.c | 20 +-
> app/test/test_ptr_add_sub.c | 199 +++++++++++++++++
Do we *need* a new file for testing new macros?
So far, everything went to test_common.c.
--
David Marchand
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-03 9:08 ` Morten Brørup
@ 2026-02-03 16:24 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-03 16:24 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
> Again, thank you for all the work you put into this, Scott!
Thanks for all the feedback :)
> > 2. integer types that represent pointers
>
> Please get rid of all the RTE_INT_PTR macros.
> IMO, these macros look too much like plain wrappers around simple +/- operators.
> It seems they are only needed for the cnxk drivers; those drivers can probably be fixed in some other way.
>
Sounds good. Looking at the current state, cnxk doesn't even need
them. Just 1 usage in eal_common_options.c I can cast and work around.
> > + RTE_ASSERT(mi);
>
> Preferred: RTE_ASSERT(mi != NULL);
Asserts updated
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-03 9:51 ` David Marchand
@ 2026-02-03 16:25 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-03 16:25 UTC (permalink / raw)
To: David Marchand; +Cc: dev, mb, stephen, bruce.richardson
> Do we *need* a new file for testing new macros?
> So far, everything went to test_common.c.
I'll move into test_common.c. I'll keep independent tests that verify
pointer types natively (existing tests use uintptr_t).
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v18 0/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-02-03 21:18 ` scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
` (2 more replies)
2 siblings, 3 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-03 21:18 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott
From: Scott <scott.k.mitch1@gmail.com>
This series addresses two issues:
1. Removes the semantically incorrect __rte_alloc_size attribute from
rte_lcore_var_alloc which was causing FORTIFY_SOURCE failures on
Ubuntu 24.04 CI. The attribute was incorrect because the function
returns a handle to per-lcore variables, not a direct pointer to
'size' bytes.
2. Improves RTE_PTR_ADD/SUB macros to preserve pointer type qualifiers
(const/volatile) and use pointer arithmetic instead of integer casts
to enable compiler optimizations and maintain pointer provenance.
The bugfix (patch 1) is placed first so it can be backported independently
to stable branches.
---
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
Scott Mitchell (2):
eal: remove alloc_size from rte_lcore_var_alloc
eal: RTE_PTR_ADD/SUB API improvements
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 307 ++++++++++++++++++--
doc/guides/rel_notes/release_26_03.rst | 12 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 158 +++++++++-
lib/eal/include/rte_lcore_var.h | 2 +-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
44 files changed, 649 insertions(+), 152 deletions(-)
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
@ 2026-02-03 21:18 ` scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-03 21:18 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell, mattias.ronnblom,
stable
From: Scott Mitchell <scott.k.mitch1@gmail.com>
The __rte_alloc_size(1) attribute on rte_lcore_var_alloc() is
semantically incorrect and causes false positives with FORTIFY_SOURCE
runtime checks.
The attribute tells the compiler that the function returns a pointer
to 'size' bytes of usable memory. However, rte_lcore_var_alloc()
actually returns a handle to a per-lcore variable scheme. The
allocator internally allocates 'size' bytes per lcore
(size * RTE_MAX_LCORE total), partitioned into per-lcore sections.
The handle points to lcore 0's copy, and accessed via
RTE_LCORE_VAR_LCORE(lcore_id, handle) which computes:
handle + (lcore_id * RTE_MAX_LCORE_VAR). Access is expected
beyond 'size' bytes beyond the returned pointer when 'lcore_id != 0'
but FORTIFY_SOURCE may terminate the program due to out of bounds
access.
This can be observed on CI with gcc 13.3.0 in lcore_var_autotest with
'*** buffer overflow detected ***: terminated' if pointer provenance
is preserved (e.g. if offsets avoid casting to uintptr_t).
Fixes: 5bce9bed67ad ("eal: add static per-lcore memory allocation facility")
Cc: mattias.ronnblom@ericsson.com
Cc: stable@dpdk.org
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
lib/eal/include/rte_lcore_var.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/eal/include/rte_lcore_var.h b/lib/eal/include/rte_lcore_var.h
index ca31dff6fd..48b022e84e 100644
--- a/lib/eal/include/rte_lcore_var.h
+++ b/lib/eal/include/rte_lcore_var.h
@@ -202,7 +202,7 @@ rte_lcore_var_lcore(unsigned int lcore_id, void *handle)
__rte_experimental
void *
rte_lcore_var_alloc(size_t size, size_t align)
- __rte_alloc_size(1) __rte_alloc_align(2);
+ __rte_alloc_align(2);
#ifdef __cplusplus
}
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v18 2/2] eal: RTE_PTR_ADD/SUB API improvements
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
@ 2026-02-03 21:18 ` scott.k.mitch1
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
2 siblings, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-03 21:18 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch splits the API on two dimensions:
1. pointer types
2. integer types that represent pointers
This split allows addressing each of the challenges above
and provides distinct APIs for the distinct use cases.
Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 307 ++++++++++++++++++--
doc/guides/rel_notes/release_26_03.rst | 12 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 ++-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 158 +++++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
43 files changed, 648 insertions(+), 151 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..8310fd87c0 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,272 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+#define TEST_BUFFER_SIZE 512
+#define MAX_OFFSET 256
+#define MAX_INCREMENT 128
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types */
+ alignas(uint64_t) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t ptr_val;
+ uintptr_t exp_floor, exp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ ptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= 16; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ exp_floor = (ptr_val / align) * align;
+ exp_ceil = ((ptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, exp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, exp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, exp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, exp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, exp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, exp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, exp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, exp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, exp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, exp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, exp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, exp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, exp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, exp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, exp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +300,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +447,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +460,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +587,26 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 15dabee7a1..7c89efb172 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -84,6 +84,18 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -). Use of ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``
+ or ``RTE_PTR_ALIGN_FLOOR`` should use ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..35685dcd80 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR(intptr) ((void *)(uintptr_t)(intptr))
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..5f3168a286 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1608,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1620,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..e789c1cdc0 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1655,8 +1655,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..a300d6d854 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +700,36 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +741,22 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..0489f1eaf3 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..a11f4841d1 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1847,7 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* [PATCH v19] eal: RTE_PTR_ADD/SUB API improvements
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
@ 2026-02-04 2:46 ` scott.k.mitch1
2026-02-04 5:20 ` Scott Mitchell
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
2 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-04 2:46 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 380 ++++++++++++++++++--
doc/guides/rel_notes/release_26_03.rst | 12 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 158 +++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
43 files changed, 721 insertions(+), 151 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..e6c1daedb2 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,345 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+#define TEST_BUFFER_SIZE 512
+#define MAX_OFFSET 256
+#define MAX_INCREMENT 128
+#define MAX_ALIGNMENT 16
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types */
+ alignas(uint64_t) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +373,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +520,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +533,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +660,26 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index a0f89b5ea2..45dd06f626 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -104,6 +104,18 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -). Use of ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``
+ or ``RTE_PTR_ALIGN_FLOOR`` should use ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..35685dcd80 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR(intptr) ((void *)(uintptr_t)(intptr))
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..5f3168a286 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1608,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1620,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..e789c1cdc0 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1655,8 +1655,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..a300d6d854 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +700,36 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +741,22 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..0489f1eaf3 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..a11f4841d1 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1847,7 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v19] eal: RTE_PTR_ADD/SUB API improvements
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
@ 2026-02-04 5:20 ` Scott Mitchell
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
1 sibling, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-04 5:20 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson
Test failure is expected until Depends-on: 160679 ("eal: add
__rte_may_alias and __rte_aligned to unaligned typedefs") is merged.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v20] eal: RTE_PTR_ADD/SUB API improvements
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
2026-02-04 5:20 ` Scott Mitchell
@ 2026-02-04 6:12 ` scott.k.mitch1
2026-02-04 22:47 ` Morten Brørup
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-04 6:12 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v20:
- Fix test_common.c test_ptr_add_sub_align failure due to alignas
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 380 ++++++++++++++++++--
doc/guides/rel_notes/release_26_03.rst | 12 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 4 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/cnxk/roc_platform.h | 2 +
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/mempool/dpaa/dpaa_mempool.c | 2 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/intel/fm10k/fm10k.h | 6 +-
drivers/net/intel/fm10k/fm10k_rxtx_vec.c | 12 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 158 +++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 1 +
lib/mbuf/rte_mbuf.h | 2 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.c | 8 +-
lib/mempool/rte_mempool.h | 3 +
lib/mempool/rte_mempool_ops_default.c | 2 +-
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
43 files changed, 721 insertions(+), 151 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..dbc398b9b2 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,345 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+#define TEST_BUFFER_SIZE 512
+#define MAX_OFFSET 256
+#define MAX_INCREMENT 128
+#define MAX_ALIGNMENT 16
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types - must be aligned to MAX_ALIGNMENT */
+ alignas(MAX_ALIGNMENT) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +373,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +520,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +533,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +660,26 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index a0f89b5ea2..45dd06f626 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -104,6 +104,18 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -). Use of ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``
+ or ``RTE_PTR_ALIGN_FLOOR`` should use ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..252658a83f 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -56,7 +56,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*32B */
offset = cpth->w2.ptr_offset;
offset = (((offset - 1) & 0x7) + 1) * 32;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
if (cpth->w0.num_frags > 0) {
cpt_dump(file, "CPT Fraginfo_0 \t%p:", frag_info);
@@ -162,7 +162,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
/* offset of 0 implies 256B, otherwise it implies offset*8B */
offset = cpth->w2.fi_offset;
offset = (((offset - 1) & 0x1f) + 1) * 8;
- frag_info = PLT_PTR_ADD(cpth, offset);
+ frag_info = PLT_PTR_ADD(PLT_PTR_UNQUAL(cpth), offset);
cpt_dump(file, "CPT Fraginfo \t0x%p:", frag_info);
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..aa24dbb82f 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].phys_addr, ML_MLAB_BLK_OFFSET));
+ PLT_PTR_ADD_U64_CAST(
+ PLT_INT_PTR(ml->pci_dev->mem_resource[0].phys_addr),
+ ML_MLAB_BLK_OFFSET));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..c42fb7e004 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = PLT_INT_PTR(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..3526ec9268 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..ae161e02ed 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return PLT_INT_PTR(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index e22a50d47a..35685dcd80 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -47,6 +47,8 @@
#define PLT_PTR_ADD RTE_PTR_ADD
#define PLT_PTR_SUB RTE_PTR_SUB
#define PLT_PTR_DIFF RTE_PTR_DIFF
+#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
+#define PLT_INT_PTR(intptr) ((void *)(uintptr_t)(intptr))
#define PLT_MAX_RXTX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
#define PLT_INTR_VEC_RXTX_OFFSET RTE_INTR_VEC_RXTX_OFFSET
#define PLT_MIN RTE_MIN
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..cd35cc3e55 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..2113a2ea78 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 64), aw4);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 80), aw5);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 96), aw6);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 32), aw2);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64(PLT_INT_PTR(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/mempool/dpaa/dpaa_mempool.c b/drivers/mempool/dpaa/dpaa_mempool.c
index 2f9395b3f4..85e1c01017 100644
--- a/drivers/mempool/dpaa/dpaa_mempool.c
+++ b/drivers/mempool/dpaa/dpaa_mempool.c
@@ -321,7 +321,7 @@ dpaa_adjust_obj_bounds(char *va, size_t *offset,
size_t off = *offset;
if (dpaa_check_obj_bounds(va + off, pg_sz, total) == false) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total - ((((size_t)va + off - 1) % total) + 1);
}
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/intel/fm10k/fm10k.h b/drivers/net/intel/fm10k/fm10k.h
index 0eb32ac0d0..4e3081785f 100644
--- a/drivers/net/intel/fm10k/fm10k.h
+++ b/drivers/net/intel/fm10k/fm10k.h
@@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t in_port)
mb->nb_segs = 1;
/* enforce 512B alignment on default Rx virtual addresses */
- mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
- RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb->buf_addr);
+ mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb->buf_addr +
+ RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb->buf_addr);
mb->port = in_port;
}
diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
index 0eada7275e..a08af75bc7 100644
--- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
+++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
@@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
_mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q), dma_addr1);
/* enforce 512B alignment on default Rx virtual addresses */
- mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb0->buf_addr);
- mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1->buf_addr
- + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
- - (char *)mb1->buf_addr);
+ mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb0->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb0->buf_addr);
+ mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb1->buf_addr
+ + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
+ (char *)mb1->buf_addr);
}
rxq->rxrearm_start += RTE_FM10K_RXQ_REARM_THRESH;
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..348040c1b9 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..5f3168a286 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1608,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1620,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..e789c1cdc0 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1655,8 +1655,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..a300d6d854 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add_ptr + (x)) : __rte_ptr_add_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub_ptr = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub_ptr - (x)) : __rte_ptr_sub_ptr); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +700,36 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_align_floor_tmp = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ /* to preserve pointer provenance for compiler optimizations */ \
+ size_t __rte_misalign = (uintptr_t)__rte_ptr_align_floor_tmp & ((align) - 1); \
+ /* (3) Return the aligned result, cast to preserve input type */ \
+ (typeof(__rte_ptr_align_floor_tmp))RTE_PTR_SUB(__rte_ptr_align_floor_tmp, __rte_misalign); \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +741,22 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..557954d45e 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..0489f1eaf3 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,7 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +290,7 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 3042d94c14..f1ff668205 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,
memhdr->opaque = opaque;
if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
- off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
else
- off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
+ off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN), vaddr);
if (off > len) {
ret = 0;
@@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr,
/* populate with the largest group of contiguous pages */
for (phys_len = RTE_MIN(
- (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
- (addr + off)),
+ (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz),
+ addr + off),
len - off);
off + phys_len < len;
phys_len = RTE_MIN(phys_len + pg_sz, len - off)) {
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index aedc100964..a11f4841d1 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,7 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +400,7 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1847,7 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/mempool/rte_mempool_ops_default.c b/lib/mempool/rte_mempool_ops_default.c
index d27d6fc473..e28a288b91 100644
--- a/lib/mempool/rte_mempool_ops_default.c
+++ b/lib/mempool/rte_mempool_ops_default.c
@@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool *mp, unsigned int flags,
for (i = 0; i < max_objs; i++) {
/* avoid objects to cross page boundaries */
if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
- off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va + off);
+ off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off, pg_sz), va + off);
if (flags & RTE_MEMPOOL_POPULATE_F_ALIGN_OBJ)
off += total_elt_sz -
(((uintptr_t)(va + off - 1) %
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [PATCH v20] eal: RTE_PTR_ADD/SUB API improvements
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
@ 2026-02-04 22:47 ` Morten Brørup
2026-02-05 6:53 ` Scott Mitchell
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
1 sibling, 1 reply; 60+ messages in thread
From: Morten Brørup @ 2026-02-04 22:47 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
> +* eal: Improved pointer arithmetic macros to preserve pointer
> provenance and type qualifiers.
> +
> + * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
> ``RTE_PTR_ALIGN_CEIL``,
> + and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers
> and use
> + pointer arithmetic instead of integer casts to enable compiler
> optimizations. These
> + macros do not nest infinitely and may require intermediate
> variables.
> + * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``,
> ``RTE_PTR_ALIGN``,
> + ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as
> undefined behavior.
> + * Existing code passing integer types as pointer to ``RTE_PTR_ADD``
> or ``RTE_PTR_SUB``
> + should use native operators (e.g. + -). Use of ``RTE_PTR_ALIGN``,
> ``RTE_PTR_ALIGN_CEIL``
> + or ``RTE_PTR_ALIGN_FLOOR`` should use ``RTE_ALIGN_CEIL`` or
> ``RTE_ALIGN_FLOOR``.
Clarify (for dummies):
"Use of RTE_PTR_ALIGN [...]
+ with integer types
should use [...]"
> --- a/drivers/common/cnxk/roc_platform.h
> +++ b/drivers/common/cnxk/roc_platform.h
> @@ -47,6 +47,8 @@
> #define PLT_PTR_ADD RTE_PTR_ADD
> #define PLT_PTR_SUB RTE_PTR_SUB
> #define PLT_PTR_DIFF RTE_PTR_DIFF
> +#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
The PLT_PTR_UNQUAL macro is only used in drivers/common/cnxk/roc_cpt_debug.c; but I think it can be avoided by changing the frag_info variable from "struct cpt_frag_info_s *frag_info;" to "const struct cpt_frag_info_s *frag_info;". Then you don't need to add the PLT_PTR_UNQUAL macro.
> +#define PLT_INT_PTR(intptr) ((void *)(uintptr_t)(intptr))
Like I didn't like the RTE_INT_PTR macros, I also don't like the PLT_INT_PTR() macro. Please get rid of it.
If an address variable is uintptr_t type, can't you cast it to void* and still use PLT_PTR_ADD()?
> --- a/drivers/net/ena/ena_ethdev.c
> +++ b/drivers/net/ena/ena_ethdev.c
> @@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device
> *dev, uint32_t bar)
> {
> const struct rte_mem_resource *res = &dev->mem_resource[bar];
> size_t offset = res->phys_addr % rte_mem_page_size();
> - void *vaddr = RTE_PTR_ADD(res->addr, offset);
> + void *vaddr;
> +
> + if (res->addr == NULL) {
> + PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL",
> bar);
> + return NULL;
> + }
> +
> + vaddr = RTE_PTR_ADD(res->addr, offset);
Note to other reviewers:
The added check for res->addr == NULL looks like an unrelated change.
But it also tells the compiler that res->addr is not NULL when used with RTE_PTR_ADD().
So it's not an unrelated change.
Multiple places in this patch.
> --- a/drivers/net/intel/fm10k/fm10k.h
> +++ b/drivers/net/intel/fm10k/fm10k.h
> @@ -264,9 +264,9 @@ fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint16_t
> in_port)
> mb->nb_segs = 1;
>
> /* enforce 512B alignment on default Rx virtual addresses */
> - mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr +
> - RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
> - - (char *)mb->buf_addr);
> + mb->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char *)mb-
> >buf_addr +
> + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN),
> + (char *)mb->buf_addr);
Is using RTE_PTR_DIFF required here? Or can the code be unchanged?
> diff --git a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
> b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
> index 0eada7275e..a08af75bc7 100644
> --- a/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
> +++ b/drivers/net/intel/fm10k/fm10k_rxtx_vec.c
> @@ -315,12 +315,12 @@ fm10k_rxq_rearm(struct fm10k_rx_queue *rxq)
> _mm_store_si128(RTE_CAST_PTR(__m128i *, &rxdp++->q),
> dma_addr1);
>
> /* enforce 512B alignment on default Rx virtual addresses
> */
> - mb0->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb0-
> >buf_addr
> - + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
> - - (char *)mb0->buf_addr);
> - mb1->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb1-
> >buf_addr
> - + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN)
> - - (char *)mb1->buf_addr);
> + mb0->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char
> *)mb0->buf_addr
> + + RTE_PKTMBUF_HEADROOM,
> FM10K_RX_DATABUF_ALIGN),
> + (char *)mb0->buf_addr);
> + mb1->data_off = (uint16_t)RTE_PTR_DIFF(RTE_PTR_ALIGN((char
> *)mb1->buf_addr
> + + RTE_PKTMBUF_HEADROOM,
> FM10K_RX_DATABUF_ALIGN),
> + (char *)mb1->buf_addr);
Same: Is using RTE_PTR_DIFF required here?
> --- a/drivers/net/mlx4/mlx4_txq.c
> +++ b/drivers/net/mlx4/mlx4_txq.c
> @@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
> void *addr;
>
> addr = ppriv->uar_table[txq->stats.idx];
> - munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
> + if (addr)
Correction: if (addr != NULL)
> + munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
> }
>
> --- a/lib/mbuf/rte_mbuf.c
> +++ b/lib/mbuf/rte_mbuf.c
> @@ -193,6 +193,7 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
>
> RTE_ASSERT(ctx->ext < ctx->ext_num);
> RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
> + RTE_ASSERT(ext_mem->buf_ptr);
>
> m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
Correction: RTE_ASSERT(ext_mem->buf_ptr != NULL);
Do we also need __rte_assume(ext_mem->buf_ptr != NULL) for when building without RTE_ENABLE_ASSERT?
If so, remember any other RTE_ASSERT()s ensuring non-NULL for RTE_PTR_ADD().
> diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
> index 3042d94c14..f1ff668205 100644
> --- a/lib/mempool/rte_mempool.c
> +++ b/lib/mempool/rte_mempool.c
> @@ -349,9 +349,9 @@ rte_mempool_populate_iova(struct rte_mempool *mp,
> char *vaddr,
> memhdr->opaque = opaque;
>
> if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN)
> - off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr;
> + off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, 8), vaddr);
> else
> - off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr;
> + off = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr,
> RTE_MEMPOOL_ALIGN), vaddr);
Same: Is using RTE_PTR_DIFF required here?
>
> if (off > len) {
> ret = 0;
> @@ -425,8 +425,8 @@ rte_mempool_populate_virt(struct rte_mempool *mp,
> char *addr,
>
> /* populate with the largest group of contiguous pages */
> for (phys_len = RTE_MIN(
> - (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) -
> - (addr + off)),
> + (size_t)RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(addr + off +
> 1, pg_sz),
> + addr + off),
Same: Is using RTE_PTR_DIFF required here?
> --- a/lib/mempool/rte_mempool_ops_default.c
> +++ b/lib/mempool/rte_mempool_ops_default.c
> @@ -117,7 +117,7 @@ rte_mempool_op_populate_helper(struct rte_mempool
> *mp, unsigned int flags,
> for (i = 0; i < max_objs; i++) {
> /* avoid objects to cross page boundaries */
> if (check_obj_bounds(va + off, pg_sz, total_elt_sz) < 0) {
> - off += RTE_PTR_ALIGN_CEIL(va + off, pg_sz) - (va +
> off);
> + off += RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(va + off,
> pg_sz), va + off);
Same: Is using RTE_PTR_DIFF required here?
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v20] eal: RTE_PTR_ADD/SUB API improvements
2026-02-04 22:47 ` Morten Brørup
@ 2026-02-05 6:53 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-05 6:53 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
> Clarify (for dummies):
> "Use of RTE_PTR_ALIGN [...]
> + with integer types
> should use [...]"
I'll add a new line to be more explicit.
> > +#define PLT_PTR_UNQUAL RTE_PTR_UNQUAL
>
> The PLT_PTR_UNQUAL macro is only used in drivers/common/cnxk/roc_cpt_debug.c; but I think it can be avoided by changing the frag_info variable from "struct cpt_frag_info_s *frag_info;" to "const struct cpt_frag_info_s *frag_info;". Then you don't need to add the PLT_PTR_UNQUAL macro.
Done.
> > +#define PLT_INT_PTR(intptr) ((void *)(uintptr_t)(intptr))
>
> Like I didn't like the RTE_INT_PTR macros, I also don't like the PLT_INT_PTR() macro. Please get rid of it.
> If an address variable is uintptr_t type, can't you cast it to void* and still use PLT_PTR_ADD()?
Done.
> Is using RTE_PTR_DIFF required here? Or can the code be unchanged?
Good catch, I will fix this and review RTE_PTR_DIFF usage.
RTE_PTR_ALIGN_CEIL is losing the ptr argument type by going through
RTE_PTR_ADD, so it results "error: invalid operands to binary - (have
‘void *’ and ‘char *’)". I will fix the PTR_ALIGN macros to preserve
return type consistently and also avoid void* cast which may impact
optimizations that are alignment aware (required by RTE_PTR_[ADD|SUB]
bcz result isn't known to be aligned).
> > + if (addr)
>
> Correction: if (addr != NULL)
>
> > + munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
Done.
> Do we also need __rte_assume(ext_mem->buf_ptr != NULL) for when building without RTE_ENABLE_ASSERT?
> If so, remember any other RTE_ASSERT()s ensuring non-NULL for RTE_PTR_ADD().
Sounds good, will do.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v21] eal: RTE_PTR_ADD/SUB API improvements
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
2026-02-04 22:47 ` Morten Brørup
@ 2026-02-05 7:03 ` scott.k.mitch1
2026-02-05 7:50 ` Morten Brørup
2026-02-06 1:01 ` [PATCH v22] " scott.k.mitch1
1 sibling, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-05 7:03 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v21:
- Fix PTR_ALIGN to preserve return type correctly, avoid void* cast
because alignment is known
- Remove unecessary PTR_DIFF usage with PTR_ALIGN due to prior fix
- Remove RTE_INT_PTR and PLT_PTR_UNQUAL
- Consistent != NULL usage, add __rte_assume
- Add edge case tests to test_common.c
v20:
- Fix test_common.c test_ptr_add_sub_align failure due to alignas
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 502 +++++++++++++++++++-
doc/guides/rel_notes/release_26_03.rst | 14 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 12 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 180 ++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 2 +
lib/mbuf/rte_mbuf.h | 4 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.h | 6 +
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
37 files changed, 860 insertions(+), 140 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..d66b6cb01f 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,466 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+/* Independent test parameters */
+#define RTE_TEST_COMMON_MAX_ALIGNMENT RTE_CACHE_LINE_SIZE
+#define RTE_TEST_COMMON_MAX_OFFSET 256
+#define RTE_TEST_COMMON_MAX_INCREMENT 128
+/* Dependent: computed based on test requirements */
+/* Extra RTE_TEST_COMMON_MAX_ALIGNMENT to ensure CEIL can round up without going out of bounds */
+#define TEST_BUFFER_SIZE (RTE_TEST_COMMON_MAX_OFFSET + RTE_TEST_COMMON_MAX_INCREMENT + \
+ (2 * RTE_TEST_COMMON_MAX_ALIGNMENT) + 16)
+
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types - must be aligned to RTE_TEST_COMMON_MAX_ALIGNMENT */
+ alignas(RTE_TEST_COMMON_MAX_ALIGNMENT) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < RTE_TEST_COMMON_MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < RTE_TEST_COMMON_MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= RTE_TEST_COMMON_MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_ptr_align_edge_cases(void)
+{
+/* Independent test parameters */
+#define RTE_COMMON_TEST_PAGE_SIZE 4096
+#define RTE_COMMON_TEST_CACHE_LINE_ALIGN RTE_CACHE_LINE_SIZE
+/* Dependent: computed based on test requirements */
+/* Must fit PAGE_SIZE alignment tests */
+#define RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+#define RTE_COMMON_TEST_DOUBLE_PAGE_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+/* Must be >= CACHE_LINE_ALIGN to prevent overflow in CEIL boundary test */
+#define RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET (2 * RTE_COMMON_TEST_CACHE_LINE_ALIGN)
+
+ /* Ensure BOUNDARY_TEST_OFFSET is large enough to prevent overflow in CEIL test */
+ /* near_max + CACHE_LINE_ALIGN - 1 must not wrap, so BOUNDARY_TEST_OFFSET >= CACHE_LINE_ALIGN */
+ RTE_BUILD_BUG_ON(RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET < RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+
+ alignas(RTE_CACHE_LINE_SIZE) char test_buffer[RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE];
+ void *result;
+ uint64_t *typed_result;
+
+ /* Initialize buffer */
+ memset(test_buffer, 0xAA, sizeof(test_buffer));
+
+ /* Test 1: Very large alignment values (page size and beyond) */
+ const size_t large_alignments[] = {RTE_COMMON_TEST_PAGE_SIZE,
+ RTE_COMMON_TEST_DOUBLE_PAGE_SIZE};
+ for (size_t i = 0; i < RTE_DIM(large_alignments); i++) {
+ size_t align = large_alignments[i];
+ void *unaligned_ptr = test_buffer + 1; /* Intentionally misaligned by 1 byte */
+
+ /* Ensure buffer is large enough for this alignment */
+ RTE_TEST_ASSERT(RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE >= align,
+ "Buffer too small for alignment %zu", align);
+
+ result = RTE_PTR_ALIGN_FLOOR(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "FLOOR with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result <= unaligned_ptr,
+ "FLOOR with alignment %zu went forward", align);
+
+ result = RTE_PTR_ALIGN_CEIL(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "CEIL with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result >= unaligned_ptr,
+ "CEIL with alignment %zu went backward", align);
+ }
+
+ /* Test 2: Address space boundary arithmetic (no dereferencing) */
+ /* Test FLOOR lower bound - pointer near zero */
+ /* Dynamically compute offset that allows FLOOR to align down without underflow */
+ uintptr_t near_zero = RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *low_ptr = (void *)near_zero;
+ uintptr_t expected_floor = (near_zero / RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_FLOOR(low_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "Low address FLOOR not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_floor,
+ "Low address FLOOR computed incorrectly: got %p, expected %p",
+ result, (void *)expected_floor);
+ RTE_TEST_ASSERT((uintptr_t)result <= near_zero,
+ "Low address FLOOR went forward");
+
+ /* Test CEIL upper bound - pointer near UINTPTR_MAX */
+ /* Compute offset that allows CEIL to align up without wrapping */
+ /* Ensure no overflow: near_max + CACHE_LINE_ALIGN - 1 must not wrap */
+ uintptr_t near_max = UINTPTR_MAX - RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *high_ptr = (void *)near_max;
+ uintptr_t expected_ceil = ((near_max + RTE_COMMON_TEST_CACHE_LINE_ALIGN - 1) /
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_CEIL(high_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "High address CEIL not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_ceil,
+ "High address CEIL computed incorrectly: got %p, expected %p",
+ result, (void *)expected_ceil);
+ RTE_TEST_ASSERT((uintptr_t)result >= near_max,
+ "High address CEIL went backward");
+
+ /* Test 3: Type preservation with extreme alignments */
+ /* Test CEIL with PAGE_SIZE - aligns upward into buffer */
+ typed_result = (uint64_t *)test_buffer;
+ typed_result = RTE_PTR_ALIGN_CEIL(typed_result, RTE_COMMON_TEST_PAGE_SIZE);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_PAGE_SIZE == 0,
+ "CEIL type preservation failed with PAGE_SIZE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "CEIL went beyond buffer bounds");
+ /* Verify we can dereference as uint64_t* (compiler should allow this) */
+ *typed_result = 0x123456789ABCDEF0ULL;
+ RTE_TEST_ASSERT(*typed_result == 0x123456789ABCDEF0ULL,
+ "CEIL type-preserved pointer dereference failed");
+
+ /* Test FLOOR with CACHE_LINE_ALIGN - buffer is guaranteed cache-line aligned */
+ /* Use cache line alignment since buffer is only guaranteed RTE_CACHE_LINE_SIZE aligned */
+ typed_result = (uint64_t *)(test_buffer + RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ typed_result = RTE_PTR_ALIGN_FLOOR(typed_result, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "FLOOR type preservation failed with CACHE_LINE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result >= (uintptr_t)test_buffer,
+ "FLOOR went before buffer start");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "FLOOR went beyond buffer bounds");
+ /* Safe to dereference now */
+ *typed_result = 0xDEADBEEFCAFEBABEULL;
+ RTE_TEST_ASSERT(*typed_result == 0xDEADBEEFCAFEBABEULL,
+ "FLOOR type-preserved pointer dereference failed");
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +494,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +641,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +654,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +781,27 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_ptr_align_edge_cases),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index a0f89b5ea2..82f79ffcd8 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -104,6 +104,20 @@ API Changes
Also, make sure to start the actual text at the margin.
=======================================================
+* eal: Improved pointer arithmetic macros to preserve pointer provenance and type qualifiers.
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -).
+ * Existing code passing integer types as pointer to ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL`` or ``RTE_PTR_ALIGN_FLOOR`` should use
+ ``RTE_ALIGN``, ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
+
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..44c47a341c 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -16,8 +16,8 @@
static inline void
cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
- struct cpt_rxc_sg_s *rxc_sg;
+ const struct cpt_frag_info_s *frag_info;
+ const struct cpt_rxc_sg_s *rxc_sg;
uint32_t offset;
int i;
@@ -94,7 +94,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
frag_info++;
}
- rxc_sg = (struct cpt_rxc_sg_s *)frag_info;
+ rxc_sg = (const struct cpt_rxc_sg_s *)frag_info;
for (i = 0; i < cpth->w4.sctr_size; i++) {
cpt_dump(file, "CPT RXC SC SGS \t%p:", rxc_sg);
cpt_dump(file, "W0: seg1_size \t0x%x\t\tseg2_size \t0x%x\t\tseg3_size \t0x%04x",
@@ -125,9 +125,9 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
static inline void
cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
+ const struct cpt_frag_info_s *frag_info;
uint32_t offset;
- uint64_t *slot;
+ const uint64_t *slot;
cpt_dump(file, "CPT_PARSE \t0x%p:", cpth);
@@ -178,7 +178,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
cpt_dump(file, "W1: frag_size2 \t0x%x", frag_info->w1.frag_size2);
cpt_dump(file, "W1: frag_size3 \t0x%x", frag_info->w1.frag_size3);
- slot = (uint64_t *)(frag_info + 1);
+ slot = (const uint64_t *)(frag_info + 1);
cpt_dump(file, "Frag Slot2: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[0]));
cpt_dump(file, "Frag Slot3: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[1]));
}
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..e82bb58943 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- 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));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..5de4fc3efe 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = (void *)(uintptr_t)(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..27f3f79c36 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..688d703fd1 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..f33c3a561a 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..8c1df3dbaf 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..26e40e5218 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr != NULL)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index c62edf5e55..5f3168a286 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1447,7 +1458,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1519,7 +1530,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1530,8 +1541,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1553,7 +1563,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1597,7 +1608,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1609,8 +1620,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 485655865d..e789c1cdc0 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1655,8 +1655,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..86647accad 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,74 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_add = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add + (x)) : __rte_ptr_add); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ /* C++ forbids void* arithmetic, but arrays decay automatically */ \
+ __rte_auto_type __rte_ptr_sub = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub - (x)) : __rte_ptr_sub); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +700,38 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_floor = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_floor_misalign = (uintptr_t)__rte_ptr_floor & ((align) - 1); \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ (typeof(__rte_ptr_floor))((char *)__rte_ptr_floor - __rte_ptr_floor_misalign); \
+ __rte_diagnostic_pop \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +743,42 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
- RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_ceil = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute alignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_ceil_align_m1 = (align) - 1; \
+ uintptr_t __rte_ptr_ceil_aligned = ((uintptr_t)__rte_ptr_ceil + __rte_ptr_ceil_align_m1) \
+ & ~__rte_ptr_ceil_align_m1; \
+ size_t __rte_ptr_ceil_offset = __rte_ptr_ceil_aligned - (uintptr_t)__rte_ptr_ceil; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ (typeof(__rte_ptr_ceil))((char *)__rte_ptr_ceil + __rte_ptr_ceil_offset); \
+ __rte_diagnostic_pop \
+}))
+#else
+/* MSVC version - uses integer arithmetic like RTE_PTR_ALIGN_FLOOR */
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+ RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 1e60e21620..f770826a43 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -835,6 +835,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 8e1763e890..3830bd5d7f 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -759,6 +759,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f61d5a273f..f2cd0db4b7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..46d3439f8a 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,8 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr != NULL);
+ __rte_assume(ext_mem->buf_ptr != NULL);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..29a147eeb9 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,8 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
+ __rte_assume(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +291,8 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
+ __rte_assume(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index 1144dca58a..2c865035a6 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,8 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
+ __rte_assume(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +401,8 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
+ __rte_assume(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1849,8 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
+ __rte_assume(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* RE: [PATCH v21] eal: RTE_PTR_ADD/SUB API improvements
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
@ 2026-02-05 7:50 ` Morten Brørup
2026-02-06 1:04 ` Scott Mitchell
2026-02-06 1:01 ` [PATCH v22] " scott.k.mitch1
1 sibling, 1 reply; 60+ messages in thread
From: Morten Brørup @ 2026-02-05 7:50 UTC (permalink / raw)
To: scott.k.mitch1, dev; +Cc: stephen, bruce.richardson
Acked-by: Morten Brørup <mb@smartsharesystems.com>
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v22] eal: RTE_PTR_ADD/SUB API improvements
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
2026-02-05 7:50 ` Morten Brørup
@ 2026-02-06 1:01 ` scott.k.mitch1
2026-02-06 4:28 ` [PATCH v23] " scott.k.mitch1
1 sibling, 1 reply; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-06 1:01 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v22:
- msvc fix RTE_PTR_ALIGN_FLOOR compile issue
v21:
- Fix PTR_ALIGN to preserve return type correctly, avoid void* cast
because alignment is known
- Remove unecessary PTR_DIFF usage with PTR_ALIGN due to prior fix
- Remove RTE_INT_PTR and PLT_PTR_UNQUAL
- Consistent != NULL usage, add __rte_assume
- Add edge case tests to test_common.c
v20:
- Fix test_common.c test_ptr_add_sub_align failure due to alignas
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 502 +++++++++++++++++++-
doc/guides/rel_notes/release_26_03.rst | 13 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 12 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 175 ++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 2 +
lib/mbuf/rte_mbuf.h | 4 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.h | 6 +
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
37 files changed, 855 insertions(+), 139 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..d66b6cb01f 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,466 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+/* Independent test parameters */
+#define RTE_TEST_COMMON_MAX_ALIGNMENT RTE_CACHE_LINE_SIZE
+#define RTE_TEST_COMMON_MAX_OFFSET 256
+#define RTE_TEST_COMMON_MAX_INCREMENT 128
+/* Dependent: computed based on test requirements */
+/* Extra RTE_TEST_COMMON_MAX_ALIGNMENT to ensure CEIL can round up without going out of bounds */
+#define TEST_BUFFER_SIZE (RTE_TEST_COMMON_MAX_OFFSET + RTE_TEST_COMMON_MAX_INCREMENT + \
+ (2 * RTE_TEST_COMMON_MAX_ALIGNMENT) + 16)
+
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types - must be aligned to RTE_TEST_COMMON_MAX_ALIGNMENT */
+ alignas(RTE_TEST_COMMON_MAX_ALIGNMENT) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < RTE_TEST_COMMON_MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < RTE_TEST_COMMON_MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= RTE_TEST_COMMON_MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_ptr_align_edge_cases(void)
+{
+/* Independent test parameters */
+#define RTE_COMMON_TEST_PAGE_SIZE 4096
+#define RTE_COMMON_TEST_CACHE_LINE_ALIGN RTE_CACHE_LINE_SIZE
+/* Dependent: computed based on test requirements */
+/* Must fit PAGE_SIZE alignment tests */
+#define RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+#define RTE_COMMON_TEST_DOUBLE_PAGE_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+/* Must be >= CACHE_LINE_ALIGN to prevent overflow in CEIL boundary test */
+#define RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET (2 * RTE_COMMON_TEST_CACHE_LINE_ALIGN)
+
+ /* Ensure BOUNDARY_TEST_OFFSET is large enough to prevent overflow in CEIL test */
+ /* near_max + CACHE_LINE_ALIGN - 1 must not wrap, so BOUNDARY_TEST_OFFSET >= CACHE_LINE_ALIGN */
+ RTE_BUILD_BUG_ON(RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET < RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+
+ alignas(RTE_CACHE_LINE_SIZE) char test_buffer[RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE];
+ void *result;
+ uint64_t *typed_result;
+
+ /* Initialize buffer */
+ memset(test_buffer, 0xAA, sizeof(test_buffer));
+
+ /* Test 1: Very large alignment values (page size and beyond) */
+ const size_t large_alignments[] = {RTE_COMMON_TEST_PAGE_SIZE,
+ RTE_COMMON_TEST_DOUBLE_PAGE_SIZE};
+ for (size_t i = 0; i < RTE_DIM(large_alignments); i++) {
+ size_t align = large_alignments[i];
+ void *unaligned_ptr = test_buffer + 1; /* Intentionally misaligned by 1 byte */
+
+ /* Ensure buffer is large enough for this alignment */
+ RTE_TEST_ASSERT(RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE >= align,
+ "Buffer too small for alignment %zu", align);
+
+ result = RTE_PTR_ALIGN_FLOOR(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "FLOOR with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result <= unaligned_ptr,
+ "FLOOR with alignment %zu went forward", align);
+
+ result = RTE_PTR_ALIGN_CEIL(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "CEIL with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result >= unaligned_ptr,
+ "CEIL with alignment %zu went backward", align);
+ }
+
+ /* Test 2: Address space boundary arithmetic (no dereferencing) */
+ /* Test FLOOR lower bound - pointer near zero */
+ /* Dynamically compute offset that allows FLOOR to align down without underflow */
+ uintptr_t near_zero = RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *low_ptr = (void *)near_zero;
+ uintptr_t expected_floor = (near_zero / RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_FLOOR(low_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "Low address FLOOR not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_floor,
+ "Low address FLOOR computed incorrectly: got %p, expected %p",
+ result, (void *)expected_floor);
+ RTE_TEST_ASSERT((uintptr_t)result <= near_zero,
+ "Low address FLOOR went forward");
+
+ /* Test CEIL upper bound - pointer near UINTPTR_MAX */
+ /* Compute offset that allows CEIL to align up without wrapping */
+ /* Ensure no overflow: near_max + CACHE_LINE_ALIGN - 1 must not wrap */
+ uintptr_t near_max = UINTPTR_MAX - RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *high_ptr = (void *)near_max;
+ uintptr_t expected_ceil = ((near_max + RTE_COMMON_TEST_CACHE_LINE_ALIGN - 1) /
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_CEIL(high_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "High address CEIL not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_ceil,
+ "High address CEIL computed incorrectly: got %p, expected %p",
+ result, (void *)expected_ceil);
+ RTE_TEST_ASSERT((uintptr_t)result >= near_max,
+ "High address CEIL went backward");
+
+ /* Test 3: Type preservation with extreme alignments */
+ /* Test CEIL with PAGE_SIZE - aligns upward into buffer */
+ typed_result = (uint64_t *)test_buffer;
+ typed_result = RTE_PTR_ALIGN_CEIL(typed_result, RTE_COMMON_TEST_PAGE_SIZE);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_PAGE_SIZE == 0,
+ "CEIL type preservation failed with PAGE_SIZE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "CEIL went beyond buffer bounds");
+ /* Verify we can dereference as uint64_t* (compiler should allow this) */
+ *typed_result = 0x123456789ABCDEF0ULL;
+ RTE_TEST_ASSERT(*typed_result == 0x123456789ABCDEF0ULL,
+ "CEIL type-preserved pointer dereference failed");
+
+ /* Test FLOOR with CACHE_LINE_ALIGN - buffer is guaranteed cache-line aligned */
+ /* Use cache line alignment since buffer is only guaranteed RTE_CACHE_LINE_SIZE aligned */
+ typed_result = (uint64_t *)(test_buffer + RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ typed_result = RTE_PTR_ALIGN_FLOOR(typed_result, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "FLOOR type preservation failed with CACHE_LINE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result >= (uintptr_t)test_buffer,
+ "FLOOR went before buffer start");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "FLOOR went beyond buffer bounds");
+ /* Safe to dereference now */
+ *typed_result = 0xDEADBEEFCAFEBABEULL;
+ RTE_TEST_ASSERT(*typed_result == 0xDEADBEEFCAFEBABEULL,
+ "FLOOR type-preserved pointer dereference failed");
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +494,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +641,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +654,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +781,27 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_ptr_align_edge_cases),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 031eaa657e..dda0cec591 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -116,6 +116,19 @@ API Changes
* cfgfile: name must be less than CFG_NAME_LEN
and value must be less than CFG_VALUE_LEN.
+* **eal: Improved pointer arithmetic macros.**
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -).
+ * Existing code passing integer types as pointer to ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL`` or ``RTE_PTR_ALIGN_FLOOR`` should use
+ ``RTE_ALIGN``, ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..44c47a341c 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -16,8 +16,8 @@
static inline void
cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
- struct cpt_rxc_sg_s *rxc_sg;
+ const struct cpt_frag_info_s *frag_info;
+ const struct cpt_rxc_sg_s *rxc_sg;
uint32_t offset;
int i;
@@ -94,7 +94,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
frag_info++;
}
- rxc_sg = (struct cpt_rxc_sg_s *)frag_info;
+ rxc_sg = (const struct cpt_rxc_sg_s *)frag_info;
for (i = 0; i < cpth->w4.sctr_size; i++) {
cpt_dump(file, "CPT RXC SC SGS \t%p:", rxc_sg);
cpt_dump(file, "W0: seg1_size \t0x%x\t\tseg2_size \t0x%x\t\tseg3_size \t0x%04x",
@@ -125,9 +125,9 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
static inline void
cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
+ const struct cpt_frag_info_s *frag_info;
uint32_t offset;
- uint64_t *slot;
+ const uint64_t *slot;
cpt_dump(file, "CPT_PARSE \t0x%p:", cpth);
@@ -178,7 +178,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
cpt_dump(file, "W1: frag_size2 \t0x%x", frag_info->w1.frag_size2);
cpt_dump(file, "W1: frag_size3 \t0x%x", frag_info->w1.frag_size3);
- slot = (uint64_t *)(frag_info + 1);
+ slot = (const uint64_t *)(frag_info + 1);
cpt_dump(file, "Frag Slot2: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[0]));
cpt_dump(file, "Frag Slot3: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[1]));
}
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..e82bb58943 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- 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));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..5de4fc3efe 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = (void *)(uintptr_t)(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..27f3f79c36 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..688d703fd1 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..f33c3a561a 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..8c1df3dbaf 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..26e40e5218 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr != NULL)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index dccf9406c5..206c99695a 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1448,7 +1459,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1520,7 +1531,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1531,8 +1542,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1554,7 +1564,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1598,7 +1609,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1610,8 +1621,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aad676a004..2e732ff8ee 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1664,8 +1664,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..7fc6ce3bf0 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,72 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_add = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add + (x)) : __rte_ptr_add); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_sub = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub - (x)) : __rte_ptr_sub); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +698,38 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_floor = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_floor_misalign = (uintptr_t)__rte_ptr_floor & ((align) - 1); \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ (typeof(__rte_ptr_floor))((char *)__rte_ptr_floor - __rte_ptr_floor_misalign); \
+ __rte_diagnostic_pop \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +741,41 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_ceil = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute alignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_ceil_align_m1 = (align) - 1; \
+ uintptr_t __rte_ptr_ceil_aligned = ((uintptr_t)__rte_ptr_ceil + __rte_ptr_ceil_align_m1) \
+ & ~__rte_ptr_ceil_align_m1; \
+ size_t __rte_ptr_ceil_offset = __rte_ptr_ceil_aligned - (uintptr_t)__rte_ptr_ceil; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ (typeof(__rte_ptr_ceil))((char *)__rte_ptr_ceil + __rte_ptr_ceil_offset); \
+ __rte_diagnostic_pop \
+}))
+#else
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index d9e8ea76b9..484ea8fc94 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -842,6 +842,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 7c4197a5b8..7198bdc0f8 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -764,6 +764,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f8d6762dbc..64c57806d7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..46d3439f8a 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,8 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr != NULL);
+ __rte_assume(ext_mem->buf_ptr != NULL);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..29a147eeb9 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,8 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
+ __rte_assume(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +291,8 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
+ __rte_assume(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index 1144dca58a..2c865035a6 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,8 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
+ __rte_assume(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +401,8 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
+ __rte_assume(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1849,8 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
+ __rte_assume(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v21] eal: RTE_PTR_ADD/SUB API improvements
2026-02-05 7:50 ` Morten Brørup
@ 2026-02-06 1:04 ` Scott Mitchell
0 siblings, 0 replies; 60+ messages in thread
From: Scott Mitchell @ 2026-02-06 1:04 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stephen, bruce.richardson
msvc build failed. I missed a cast in RTE_PTR_ALIGN_CEIL return value
of RTE_PTR_ADD, fixed and v22 submitted
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v23] eal: RTE_PTR_ADD/SUB API improvements
2026-02-06 1:01 ` [PATCH v22] " scott.k.mitch1
@ 2026-02-06 4:28 ` scott.k.mitch1
2026-02-06 16:09 ` Stephen Hemminger
2026-02-07 1:45 ` [PATCH v24] " scott.k.mitch1
0 siblings, 2 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-06 4:28 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v23:
- Fix RTE_PTR_ALIGN_CEIL and RTE_PTR_ALIGN_FLOOR compiler errors
on some platforms by pop pragma then return temp
- Fix checkpatch style issues in test_common.c
v22:
- msvc fix RTE_PTR_ALIGN_FLOOR compile issue
v21:
- Fix PTR_ALIGN to preserve return type correctly, avoid void* cast
because alignment is known
- Remove unecessary PTR_DIFF usage with PTR_ALIGN due to prior fix
- Remove RTE_INT_PTR and PLT_PTR_UNQUAL
- Consistent != NULL usage, add __rte_assume
- Add edge case tests to test_common.c
v20:
- Fix test_common.c test_ptr_add_sub_align failure due to alignas
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 504 +++++++++++++++++++-
doc/guides/rel_notes/release_26_03.rst | 13 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 12 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 179 ++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 2 +
lib/mbuf/rte_mbuf.h | 4 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.h | 6 +
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
37 files changed, 861 insertions(+), 139 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..d3ec2cf66d 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,468 @@
{printf(x "() test failed!\n");\
return -1;}
+static int
+test_ptr_add_sub_align(void)
+{
+/* Independent test parameters */
+#define RTE_TEST_COMMON_MAX_ALIGNMENT RTE_CACHE_LINE_SIZE
+#define RTE_TEST_COMMON_MAX_OFFSET 256
+#define RTE_TEST_COMMON_MAX_INCREMENT 128
+/* Dependent: computed based on test requirements */
+/* Extra RTE_TEST_COMMON_MAX_ALIGNMENT to ensure CEIL can round up without going out of bounds */
+#define TEST_BUFFER_SIZE (RTE_TEST_COMMON_MAX_OFFSET + RTE_TEST_COMMON_MAX_INCREMENT + \
+ (2 * RTE_TEST_COMMON_MAX_ALIGNMENT) + 16)
+
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types */
+ alignas(RTE_TEST_COMMON_MAX_ALIGNMENT) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < RTE_TEST_COMMON_MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < RTE_TEST_COMMON_MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= RTE_TEST_COMMON_MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_ptr_align_edge_cases(void)
+{
+/* Independent test parameters */
+#define RTE_COMMON_TEST_PAGE_SIZE 4096
+#define RTE_COMMON_TEST_CACHE_LINE_ALIGN RTE_CACHE_LINE_SIZE
+/* Dependent: computed based on test requirements */
+/* Must fit PAGE_SIZE alignment tests */
+#define RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+#define RTE_COMMON_TEST_DOUBLE_PAGE_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+/* Must be >= CACHE_LINE_ALIGN to prevent overflow in CEIL boundary test */
+#define RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET (2 * RTE_COMMON_TEST_CACHE_LINE_ALIGN)
+
+ /* Ensure BOUNDARY_TEST_OFFSET is large enough to prevent overflow in CEIL test */
+ /* near_max + CACHE_LINE_ALIGN - 1 must not wrap, so
+ * BOUNDARY_TEST_OFFSET >= CACHE_LINE_ALIGN.
+ */
+ RTE_BUILD_BUG_ON(RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET < RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+
+ alignas(RTE_CACHE_LINE_SIZE) char test_buffer[RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE];
+ void *result;
+ uint64_t *typed_result;
+
+ /* Initialize buffer */
+ memset(test_buffer, 0xAA, sizeof(test_buffer));
+
+ /* Test 1: Very large alignment values (page size and beyond) */
+ const size_t large_alignments[] = {RTE_COMMON_TEST_PAGE_SIZE,
+ RTE_COMMON_TEST_DOUBLE_PAGE_SIZE};
+ for (size_t i = 0; i < RTE_DIM(large_alignments); i++) {
+ size_t align = large_alignments[i];
+ void *unaligned_ptr = test_buffer + 1; /* Intentionally misaligned by 1 byte */
+
+ /* Ensure buffer is large enough for this alignment */
+ RTE_TEST_ASSERT(align <= RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "Buffer too small for alignment %zu", align);
+
+ result = RTE_PTR_ALIGN_FLOOR(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "FLOOR with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result <= unaligned_ptr,
+ "FLOOR with alignment %zu went forward", align);
+
+ result = RTE_PTR_ALIGN_CEIL(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "CEIL with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result >= unaligned_ptr,
+ "CEIL with alignment %zu went backward", align);
+ }
+
+ /* Test 2: Address space boundary arithmetic (no dereferencing) */
+ /* Test FLOOR lower bound - pointer near zero */
+ /* Dynamically compute offset that allows FLOOR to align down without underflow */
+ uintptr_t near_zero = RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *low_ptr = (void *)near_zero;
+ uintptr_t expected_floor = (near_zero / RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_FLOOR(low_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "Low address FLOOR not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_floor,
+ "Low address FLOOR computed incorrectly: got %p, expected %p",
+ result, (void *)expected_floor);
+ RTE_TEST_ASSERT((uintptr_t)result <= near_zero,
+ "Low address FLOOR went forward");
+
+ /* Test CEIL upper bound - pointer near UINTPTR_MAX */
+ /* Compute offset that allows CEIL to align up without wrapping */
+ /* Ensure no overflow: near_max + CACHE_LINE_ALIGN - 1 must not wrap */
+ uintptr_t near_max = UINTPTR_MAX - RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *high_ptr = (void *)near_max;
+ uintptr_t expected_ceil = ((near_max + RTE_COMMON_TEST_CACHE_LINE_ALIGN - 1) /
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_CEIL(high_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "High address CEIL not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_ceil,
+ "High address CEIL computed incorrectly: got %p, expected %p",
+ result, (void *)expected_ceil);
+ RTE_TEST_ASSERT((uintptr_t)result >= near_max,
+ "High address CEIL went backward");
+
+ /* Test 3: Type preservation with extreme alignments */
+ /* Test CEIL with PAGE_SIZE - aligns upward into buffer */
+ typed_result = (uint64_t *)test_buffer;
+ typed_result = RTE_PTR_ALIGN_CEIL(typed_result, RTE_COMMON_TEST_PAGE_SIZE);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_PAGE_SIZE == 0,
+ "CEIL type preservation failed with PAGE_SIZE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "CEIL went beyond buffer bounds");
+ /* Verify we can dereference as uint64_t* (compiler should allow this) */
+ *typed_result = 0x123456789ABCDEF0ULL;
+ RTE_TEST_ASSERT(*typed_result == 0x123456789ABCDEF0ULL,
+ "CEIL type-preserved pointer dereference failed");
+
+ /* Test FLOOR with CACHE_LINE_ALIGN - buffer is guaranteed cache-line aligned */
+ /* Use cache line alignment since buffer is only guaranteed RTE_CACHE_LINE_SIZE aligned */
+ typed_result = (uint64_t *)(test_buffer + RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ typed_result = RTE_PTR_ALIGN_FLOOR(typed_result, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "FLOOR type preservation failed with CACHE_LINE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result >= (uintptr_t)test_buffer,
+ "FLOOR went before buffer start");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "FLOOR went beyond buffer bounds");
+ /* Safe to dereference now */
+ *typed_result = 0xDEADBEEFCAFEBABEULL;
+ RTE_TEST_ASSERT(*typed_result == 0xDEADBEEFCAFEBABEULL,
+ "FLOOR type-preserved pointer dereference failed");
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +496,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +643,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +656,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +783,27 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_ptr_align_edge_cases),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 031eaa657e..dda0cec591 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -116,6 +116,19 @@ API Changes
* cfgfile: name must be less than CFG_NAME_LEN
and value must be less than CFG_VALUE_LEN.
+* **eal: Improved pointer arithmetic macros.**
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -).
+ * Existing code passing integer types as pointer to ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL`` or ``RTE_PTR_ALIGN_FLOOR`` should use
+ ``RTE_ALIGN``, ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..44c47a341c 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -16,8 +16,8 @@
static inline void
cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
- struct cpt_rxc_sg_s *rxc_sg;
+ const struct cpt_frag_info_s *frag_info;
+ const struct cpt_rxc_sg_s *rxc_sg;
uint32_t offset;
int i;
@@ -94,7 +94,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
frag_info++;
}
- rxc_sg = (struct cpt_rxc_sg_s *)frag_info;
+ rxc_sg = (const struct cpt_rxc_sg_s *)frag_info;
for (i = 0; i < cpth->w4.sctr_size; i++) {
cpt_dump(file, "CPT RXC SC SGS \t%p:", rxc_sg);
cpt_dump(file, "W0: seg1_size \t0x%x\t\tseg2_size \t0x%x\t\tseg3_size \t0x%04x",
@@ -125,9 +125,9 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
static inline void
cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
+ const struct cpt_frag_info_s *frag_info;
uint32_t offset;
- uint64_t *slot;
+ const uint64_t *slot;
cpt_dump(file, "CPT_PARSE \t0x%p:", cpth);
@@ -178,7 +178,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
cpt_dump(file, "W1: frag_size2 \t0x%x", frag_info->w1.frag_size2);
cpt_dump(file, "W1: frag_size3 \t0x%x", frag_info->w1.frag_size3);
- slot = (uint64_t *)(frag_info + 1);
+ slot = (const uint64_t *)(frag_info + 1);
cpt_dump(file, "Frag Slot2: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[0]));
cpt_dump(file, "Frag Slot3: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[1]));
}
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..e82bb58943 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- 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));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..5de4fc3efe 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = (void *)(uintptr_t)(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..27f3f79c36 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..688d703fd1 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..f33c3a561a 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..8c1df3dbaf 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..26e40e5218 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr != NULL)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index dccf9406c5..206c99695a 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1448,7 +1459,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1520,7 +1531,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1531,8 +1542,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1554,7 +1564,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1598,7 +1609,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1610,8 +1621,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aad676a004..2e732ff8ee 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1664,8 +1664,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..86b0a75bb3 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,72 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_add = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add + (x)) : __rte_ptr_add); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_sub = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub - (x)) : __rte_ptr_sub); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +698,40 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_floor = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_floor_misalign = (uintptr_t)__rte_ptr_floor & ((align) - 1); \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ __rte_auto_type __rte_ptr_floor_res = \
+ (typeof(__rte_ptr_floor))((char *)__rte_ptr_floor - __rte_ptr_floor_misalign); \
+ __rte_diagnostic_pop \
+ __rte_ptr_floor_res; \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +743,43 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_ceil = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute alignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_ceil_align_m1 = (align) - 1; \
+ uintptr_t __rte_ptr_ceil_aligned = ((uintptr_t)__rte_ptr_ceil + __rte_ptr_ceil_align_m1) \
+ & ~__rte_ptr_ceil_align_m1; \
+ size_t __rte_ptr_ceil_offset = __rte_ptr_ceil_aligned - (uintptr_t)__rte_ptr_ceil; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ __rte_auto_type __rte_ptr_ceil_res = \
+ (typeof(__rte_ptr_ceil))((char *)__rte_ptr_ceil + __rte_ptr_ceil_offset); \
+ __rte_diagnostic_pop \
+ __rte_ptr_ceil_res; \
+}))
+#else
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index d9e8ea76b9..484ea8fc94 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -842,6 +842,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 7c4197a5b8..7198bdc0f8 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -764,6 +764,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f8d6762dbc..64c57806d7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..46d3439f8a 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,8 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr != NULL);
+ __rte_assume(ext_mem->buf_ptr != NULL);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..29a147eeb9 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,8 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
+ __rte_assume(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +291,8 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
+ __rte_assume(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index 1144dca58a..2c865035a6 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,8 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
+ __rte_assume(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +401,8 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
+ __rte_assume(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1849,8 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
+ __rte_assume(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
* Re: [PATCH v23] eal: RTE_PTR_ADD/SUB API improvements
2026-02-06 4:28 ` [PATCH v23] " scott.k.mitch1
@ 2026-02-06 16:09 ` Stephen Hemminger
2026-02-07 1:45 ` [PATCH v24] " scott.k.mitch1
1 sibling, 0 replies; 60+ messages in thread
From: Stephen Hemminger @ 2026-02-06 16:09 UTC (permalink / raw)
To: scott.k.mitch1; +Cc: dev, mb, bruce.richardson
On Thu, 5 Feb 2026 20:28:14 -0800
scott.k.mitch1@gmail.com wrote:
> +static int
> +test_ptr_align_edge_cases(void)
> +{
> +/* Independent test parameters */
> +#define RTE_COMMON_TEST_PAGE_SIZE 4096
> +#define RTE_COMMON_TEST_CACHE_LINE_ALIGN RTE_CACHE_LINE_SIZE
> +/* Dependent: computed based on test requirements */
> +/* Must fit PAGE_SIZE alignment tests */
> +#define RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
> +#define RTE_COMMON_TEST_DOUBLE_PAGE_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
> +/* Must be >= CACHE_LINE_ALIGN to prevent overflow in CEIL boundary test */
> +#define RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET (2 * RTE_COMMON_TEST_CACHE_LINE_ALIGN)
> +
Code reads better if #define's are put outside the function.
#define's don't have scope
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v24] eal: RTE_PTR_ADD/SUB API improvements
2026-02-06 4:28 ` [PATCH v23] " scott.k.mitch1
2026-02-06 16:09 ` Stephen Hemminger
@ 2026-02-07 1:45 ` scott.k.mitch1
1 sibling, 0 replies; 60+ messages in thread
From: scott.k.mitch1 @ 2026-02-07 1:45 UTC (permalink / raw)
To: dev; +Cc: mb, stephen, bruce.richardson, Scott Mitchell
From: Scott Mitchell <scott.k.mitch1@gmail.com>
RTE_PTR_ADD and RTE_PTR_SUB APIs have a few limitations:
1. ptr cast to uintptr_t drops pointer provenance and
prevents compiler optimizations
2. return cast discards qualifiers (const, volatile)
which may hide correctness/concurrency issues.
3. Accepts both "pointers" and "integers as pointers" which
overloads the use case and constrains the implementation
to address other challenges.
This patch removes support for integer types which allows
addressing each of the challenges above. Examples:
1. Clang is able to optimize and improve __rte_raw_cksum
(which uses RTE_PTR_ADD) by ~40% (100 bytes) to ~8x (1.5k bytes)
TSC cycles/byte.
2. Refactoring discovered cases that dropped qualifiers (volatile)
that the new API exposes.
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
Depends-on: patch-160679 ("eal: add __rte_may_alias and __rte_aligned to unaligned typedefs")
v24:
- test_common.c move defines outside function scope
v23:
- Fix RTE_PTR_ALIGN_CEIL and RTE_PTR_ALIGN_FLOOR compiler errors
on some platforms by pop pragma then return temp
- Fix checkpatch style issues in test_common.c
v22:
- msvc fix RTE_PTR_ALIGN_FLOOR compile issue
v21:
- Fix PTR_ALIGN to preserve return type correctly, avoid void* cast
because alignment is known
- Remove unecessary PTR_DIFF usage with PTR_ALIGN due to prior fix
- Remove RTE_INT_PTR and PLT_PTR_UNQUAL
- Consistent != NULL usage, add __rte_assume
- Add edge case tests to test_common.c
v20:
- Fix test_common.c test_ptr_add_sub_align failure due to alignas
v19:
- Remove first patch from series (already merged)
- Fix test_common.c test_ptr_add_sub_align failure, enhance test
v18:
- Removed RTE_INT_PTR* macros
- Explicit NULL compare in asserts
- Consolidated test_ptr_add_sub.c into test_common.c
v17:
- Improved release notes to explicitly list macro names for search/indexing
- eal_common_fbarray.c RTE_ASSERT to runtime NULL check
v16:
- Fixed test_common.c: parenthesize PTR_DIFF in RTE_INT_PTR tests
v15:
- Fixed __rte_alloc_size, spilt into 2 patch series
- Replaced RTE_INT_PTR_ADD/SUB with simpler RTE_INT_PTR(val) macro
users do int arithmetic directly: RTE_INT_PTR(addr + offset)
v14:
- fixed cpp compiler error, avoiding array pointer decay
which is implicitly done in cpp (but not c)
- fixed MALLOC_ELEM_TRAILER const preservation compile error
v13:
- Added release notes documenting API changes
- Fixed alignment in test file: use alignas(uint32_t) for buffer
- Fixed NULL pointer handling in cdx_vfio.c: check base_va before RTE_PTR_ADD
- Added GCC array-bounds diagnostic suppression in malloc_elem_from_data()
- Added bug tracker reference for volatile cast issue in idxd_pci.c
- Improved __rte_auto_type documentation: added C++11 and C23 support
- Moved doxygen rationale for void* return type to @return blocks
- Fixed MALLOC_ELEM_TRAILER to use RTE_PTR_UNQUAL for write operations
v12:
- void* return type to avoid optimizations assuming
aligned access which isn't generally safe/true.
v11:
- Split API into PTR and INT_PTR variants, update all usage
of PTR API for new APIs.
v10:
- Use unit_test_suite_runner for easier subtest failure identification
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
app/test-pmd/cmdline_flow.c | 4 +-
app/test/test_common.c | 504 +++++++++++++++++++-
doc/guides/rel_notes/release_26_03.rst | 13 +
drivers/bus/cdx/cdx_vfio.c | 13 +-
drivers/bus/pci/linux/pci.c | 6 +-
drivers/bus/vmbus/linux/vmbus_uio.c | 6 +-
drivers/common/cnxk/roc_cpt_debug.c | 12 +-
drivers/common/cnxk/roc_ml.c | 4 +-
drivers/common/cnxk/roc_nix_bpf.c | 2 +-
drivers/common/cnxk/roc_nix_inl.h | 4 +-
drivers/common/cnxk/roc_nix_inl_dp.h | 8 +-
drivers/common/mlx5/mlx5_common_mr.c | 2 +-
drivers/dma/idxd/idxd_pci.c | 11 +-
drivers/dma/odm/odm_dmadev.c | 4 +-
drivers/event/cnxk/cn10k_worker.c | 32 +-
drivers/event/cnxk/cn20k_worker.c | 32 +-
drivers/mempool/bucket/rte_mempool_bucket.c | 7 +-
drivers/net/cxgbe/sge.c | 4 +-
drivers/net/ena/ena_ethdev.c | 9 +-
drivers/net/mlx4/mlx4_txq.c | 3 +-
lib/eal/common/eal_common_fbarray.c | 3 +-
lib/eal/common/eal_common_memory.c | 32 +-
lib/eal/common/eal_common_options.c | 3 +-
lib/eal/common/malloc_elem.h | 34 +-
lib/eal/freebsd/eal_memory.c | 4 +
lib/eal/include/rte_common.h | 179 ++++++-
lib/eal/linux/eal_memalloc.c | 6 +
lib/eal/linux/eal_memory.c | 7 +
lib/eal/windows/eal_memalloc.c | 6 +
lib/graph/rte_graph.h | 4 +-
lib/latencystats/rte_latencystats.c | 3 +
lib/mbuf/rte_mbuf.c | 2 +
lib/mbuf/rte_mbuf.h | 4 +
lib/member/rte_xxh64_avx512.h | 6 +-
lib/mempool/rte_mempool.h | 6 +
lib/pdcp/pdcp_entity.h | 8 +-
lib/vhost/vhost_user.c | 13 +-
37 files changed, 861 insertions(+), 139 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ebc036b14b..8c2fc6c7b6 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -12468,7 +12468,7 @@ parse_meter_color(struct context *ctx, const struct token *token,
if (!arg)
return -1;
- *(int *)RTE_PTR_ADD(action->conf, arg->offset) = i;
+ *(int *)RTE_PTR_ADD(RTE_PTR_UNQUAL(action->conf), arg->offset) = i;
} else {
((struct rte_flow_item_meter_color *)
ctx->object)->color = (enum rte_color)i;
@@ -13351,7 +13351,7 @@ indirect_action_flow_conf_create(const struct buffer *in)
indlst_conf = NULL;
goto end;
}
- indlst_conf->conf = RTE_PTR_ADD(indlst_conf, base + len);
+ indlst_conf->conf = (const void **)RTE_PTR_ADD(indlst_conf, base + len);
for (i = 0; i < indlst_conf->conf_num; i++)
indlst_conf->conf[i] = indlst_conf->actions[i].conf;
SLIST_INSERT_HEAD(&indlst_conf_head, indlst_conf, next);
diff --git a/app/test/test_common.c b/app/test/test_common.c
index 3e1c7df0c1..b97db80c0d 100644
--- a/app/test/test_common.c
+++ b/app/test/test_common.c
@@ -20,9 +20,468 @@
{printf(x "() test failed!\n");\
return -1;}
+/* test_ptr_add_sub_align independent test parameters */
+#define RTE_TEST_COMMON_MAX_ALIGNMENT RTE_CACHE_LINE_SIZE
+#define RTE_TEST_COMMON_MAX_OFFSET 256
+#define RTE_TEST_COMMON_MAX_INCREMENT 128
+/* test_ptr_add_sub_align dependent: computed based on test requirements */
+/* Extra RTE_TEST_COMMON_MAX_ALIGNMENT to ensure CEIL can round up without going out of bounds */
+#define TEST_BUFFER_SIZE (RTE_TEST_COMMON_MAX_OFFSET + RTE_TEST_COMMON_MAX_INCREMENT + \
+ (2 * RTE_TEST_COMMON_MAX_ALIGNMENT) + 16)
+
+/* test_ptr_align_edge_cases independent test parameters */
+#define RTE_COMMON_TEST_PAGE_SIZE 4096
+#define RTE_COMMON_TEST_CACHE_LINE_ALIGN RTE_CACHE_LINE_SIZE
+/* test_ptr_align_edge_cases dependent: computed based on test requirements */
+/* Must fit PAGE_SIZE alignment tests */
+#define RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+#define RTE_COMMON_TEST_DOUBLE_PAGE_SIZE (2 * RTE_COMMON_TEST_PAGE_SIZE)
+/* Must be >= CACHE_LINE_ALIGN to prevent overflow in CEIL boundary test */
+#define RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET (2 * RTE_COMMON_TEST_CACHE_LINE_ALIGN)
+
+static int
+test_ptr_add_sub_align(void)
+{
+ /* Unaligned buffer for testing unaligned pointer types */
+ char unaligned_buffer[TEST_BUFFER_SIZE];
+ /* Aligned buffer for testing aligned pointer types */
+ alignas(RTE_TEST_COMMON_MAX_ALIGNMENT) char aligned_buffer[TEST_BUFFER_SIZE];
+ size_t offset;
+ uint8_t uval, aval;
+ uint16_t u16_uval, u16_aval;
+ uint32_t u32_uval, u32_aval;
+ uint64_t u64_uval, u64_aval;
+
+ uval = (uint8_t)rte_rand();
+ aval = (uint8_t)rte_rand();
+ if (uval == aval)
+ aval = (uint8_t)~aval;
+
+ /* Compute expected values for each type width by replicating byte pattern */
+ memset(&u16_uval, uval, sizeof(u16_uval));
+ memset(&u16_aval, aval, sizeof(u16_aval));
+ memset(&u32_uval, uval, sizeof(u32_uval));
+ memset(&u32_aval, aval, sizeof(u32_aval));
+ memset(&u64_uval, uval, sizeof(u64_uval));
+ memset(&u64_aval, aval, sizeof(u64_aval));
+
+ /* Initialize buffers - prevents compiler optimization and tests unaligned access */
+ memset(unaligned_buffer, uval, sizeof(unaligned_buffer));
+ memset(aligned_buffer, aval, sizeof(aligned_buffer));
+
+ /* Test various offsets to ensure correctness across memory range */
+ for (offset = 0; offset < RTE_TEST_COMMON_MAX_OFFSET; offset++) {
+ void *ubase = unaligned_buffer + offset;
+ void *abase = aligned_buffer + offset;
+ size_t increment;
+
+ /* Test different increment values */
+ for (increment = 0; increment < RTE_TEST_COMMON_MAX_INCREMENT; increment++) {
+ void *result;
+ char *cp_result;
+ const void *cvp_result;
+ unaligned_uint16_t *u16p_result;
+ unaligned_uint32_t *u32p_result;
+ unaligned_uint64_t *u64p_result;
+ uintptr_t uptr_val, aptr_val;
+ uintptr_t uexp_floor, uexp_ceil, aexp_floor, aexp_ceil;
+ size_t align;
+
+ /* Test void* ADD and SUB using unaligned buffer */
+ result = RTE_PTR_ADD(ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(result, (void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for void* at offset=%zu inc=%zu",
+ offset, increment);
+ result = RTE_PTR_SUB(result, increment);
+ RTE_TEST_ASSERT_EQUAL(result, ubase,
+ "RTE_PTR_SUB for void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test char* type preservation using unaligned buffer */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase + increment,
+ "RTE_PTR_ADD for char* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL((unsigned char)*cp_result, (unsigned char)uval,
+ "char* dereference at offset=%zu inc=%zu",
+ offset, increment);
+ cp_result = RTE_PTR_SUB(cp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cp_result, (char *)ubase,
+ "RTE_PTR_SUB for char* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test const void* preservation using unaligned buffer */
+ cvp_result = RTE_PTR_ADD((const void *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result,
+ (const void *)((char *)ubase + increment),
+ "RTE_PTR_ADD for const void* at offset=%zu inc=%zu",
+ offset, increment);
+ cvp_result = RTE_PTR_SUB(cvp_result, increment);
+ RTE_TEST_ASSERT_EQUAL(cvp_result, (const void *)ubase,
+ "RTE_PTR_SUB for const void* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint16_t* using unaligned buffer */
+ u16p_result = RTE_PTR_ADD((unaligned_uint16_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result,
+ (unaligned_uint16_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u16* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u16p_result, u16_uval,
+ "unaligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u16p_result = RTE_PTR_SUB(u16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u16p_result, (unaligned_uint16_t *)ubase,
+ "RTE_PTR_SUB for u16* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint32_t* using unaligned buffer */
+ u32p_result = RTE_PTR_ADD((unaligned_uint32_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result,
+ (unaligned_uint32_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u32* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u32p_result, u32_uval,
+ "unaligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u32p_result = RTE_PTR_SUB(u32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u32p_result, (unaligned_uint32_t *)ubase,
+ "RTE_PTR_SUB for u32* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test unaligned_uint64_t* using unaligned buffer */
+ u64p_result = RTE_PTR_ADD((unaligned_uint64_t *)ubase, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result,
+ (unaligned_uint64_t *)((char *)ubase + increment),
+ "RTE_PTR_ADD for u64* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*u64p_result, u64_uval,
+ "unaligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ u64p_result = RTE_PTR_SUB(u64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(u64p_result, (unaligned_uint64_t *)ubase,
+ "RTE_PTR_SUB for u64* at offset=%zu inc=%zu",
+ offset, increment);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0) {
+ uint16_t *a16p_result;
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result,
+ (uint16_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "aligned u16 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a16p_result = RTE_PTR_SUB(a16p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a16p_result, (uint16_t *)abase,
+ "RTE_PTR_SUB for uint16_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0) {
+ uint32_t *a32p_result;
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result,
+ (uint32_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "aligned u32 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a32p_result = RTE_PTR_SUB(a32p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a32p_result, (uint32_t *)abase,
+ "RTE_PTR_SUB for uint32_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0) {
+ uint64_t *a64p_result;
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result,
+ (uint64_t *)((char *)abase + increment),
+ "RTE_PTR_ADD for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "aligned u64 dereference at offset=%zu inc=%zu",
+ offset, increment);
+ a64p_result = RTE_PTR_SUB(a64p_result, increment);
+ RTE_TEST_ASSERT_EQUAL(a64p_result, (uint64_t *)abase,
+ "RTE_PTR_SUB for uint64_t* at offset=%zu inc=%zu",
+ offset, increment);
+ }
+
+ /* Test alignment functions with various alignments */
+ uptr_val = (uintptr_t)RTE_PTR_ADD(ubase, increment);
+ aptr_val = (uintptr_t)RTE_PTR_ADD(abase, increment);
+
+ /* Test power-of-2 alignments: 1, 2, 4, 8, 16 */
+ for (align = 1; align <= RTE_TEST_COMMON_MAX_ALIGNMENT; align <<= 1) {
+ /* Compute expected values using arithmetic, not masking */
+ uexp_floor = (uptr_val / align) * align;
+ uexp_ceil = ((uptr_val + align - 1) / align) * align;
+ aexp_floor = (aptr_val / align) * align;
+ aexp_ceil = ((aptr_val + align - 1) / align) * align;
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_FLOOR(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_floor,
+ "ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_FLOOR not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN_CEIL(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result % align, 0,
+ "ALIGN_CEIL not aligned offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ result = RTE_PTR_ADD(ubase, increment);
+ result = RTE_PTR_ALIGN(result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)result, uexp_ceil,
+ "ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test type preservation */
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_FLOOR(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_floor,
+ "char* ALIGN_FLOOR offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN_CEIL(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN_CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ cp_result = RTE_PTR_ADD((char *)ubase, increment);
+ cp_result = RTE_PTR_ALIGN(cp_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)cp_result, uexp_ceil,
+ "char* ALIGN != CEIL offset=%zu inc=%zu align=%zu",
+ offset, increment, align);
+
+ /* Test aligned uint16_t* at 2-byte aligned offsets */
+ if (offset % sizeof(uint16_t) == 0 && align >= sizeof(uint16_t)) {
+ uint16_t *a16p_result;
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_FLOOR(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_floor,
+ "uint16_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN_CEIL(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a16p_result = RTE_PTR_ADD((uint16_t *)abase, increment);
+ a16p_result = RTE_PTR_ALIGN(a16p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a16p_result, aexp_ceil,
+ "uint16_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a16p_result, u16_aval,
+ "uint16_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint32_t* at 4-byte aligned offsets */
+ if (offset % sizeof(uint32_t) == 0 && align >= sizeof(uint32_t)) {
+ uint32_t *a32p_result;
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_FLOOR(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_floor,
+ "uint32_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN_CEIL(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a32p_result = RTE_PTR_ADD((uint32_t *)abase, increment);
+ a32p_result = RTE_PTR_ALIGN(a32p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a32p_result, aexp_ceil,
+ "uint32_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a32p_result, u32_aval,
+ "uint32_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+
+ /* Test aligned uint64_t* at 8-byte aligned offsets */
+ if (offset % sizeof(uint64_t) == 0 && align >= sizeof(uint64_t)) {
+ uint64_t *a64p_result;
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_FLOOR(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_floor,
+ "uint64_t* ALIGN_FLOOR offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_FLOOR dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN_CEIL(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN_CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN_CEIL dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+
+ a64p_result = RTE_PTR_ADD((uint64_t *)abase, increment);
+ a64p_result = RTE_PTR_ALIGN(a64p_result, align);
+ RTE_TEST_ASSERT_EQUAL((uintptr_t)a64p_result, aexp_ceil,
+ "uint64_t* ALIGN != CEIL offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ RTE_TEST_ASSERT_EQUAL(*a64p_result, u64_aval,
+ "uint64_t* ALIGN dereference offset=%zu inc=%zu "
+ "align=%zu", offset, increment, align);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_ptr_align_edge_cases(void)
+{
+ /* Ensure BOUNDARY_TEST_OFFSET is large enough to prevent overflow in CEIL test */
+ /* near_max + CACHE_LINE_ALIGN - 1 must not wrap, so
+ * BOUNDARY_TEST_OFFSET >= CACHE_LINE_ALIGN.
+ */
+ RTE_BUILD_BUG_ON(RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET < RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+
+ alignas(RTE_CACHE_LINE_SIZE) char test_buffer[RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE];
+ void *result;
+ uint64_t *typed_result;
+
+ /* Initialize buffer */
+ memset(test_buffer, 0xAA, sizeof(test_buffer));
+
+ /* Test 1: Very large alignment values (page size and beyond) */
+ const size_t large_alignments[] = {RTE_COMMON_TEST_PAGE_SIZE,
+ RTE_COMMON_TEST_DOUBLE_PAGE_SIZE};
+ for (size_t i = 0; i < RTE_DIM(large_alignments); i++) {
+ size_t align = large_alignments[i];
+ void *unaligned_ptr = test_buffer + 1; /* Intentionally misaligned by 1 byte */
+
+ /* Ensure buffer is large enough for this alignment */
+ RTE_TEST_ASSERT(align <= RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "Buffer too small for alignment %zu", align);
+
+ result = RTE_PTR_ALIGN_FLOOR(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "FLOOR with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result <= unaligned_ptr,
+ "FLOOR with alignment %zu went forward", align);
+
+ result = RTE_PTR_ALIGN_CEIL(unaligned_ptr, align);
+ RTE_TEST_ASSERT((uintptr_t)result % align == 0,
+ "CEIL with alignment %zu not aligned", align);
+ RTE_TEST_ASSERT(result >= unaligned_ptr,
+ "CEIL with alignment %zu went backward", align);
+ }
+
+ /* Test 2: Address space boundary arithmetic (no dereferencing) */
+ /* Test FLOOR lower bound - pointer near zero */
+ /* Dynamically compute offset that allows FLOOR to align down without underflow */
+ uintptr_t near_zero = RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *low_ptr = (void *)near_zero;
+ uintptr_t expected_floor = (near_zero / RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_FLOOR(low_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "Low address FLOOR not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_floor,
+ "Low address FLOOR computed incorrectly: got %p, expected %p",
+ result, (void *)expected_floor);
+ RTE_TEST_ASSERT((uintptr_t)result <= near_zero,
+ "Low address FLOOR went forward");
+
+ /* Test CEIL upper bound - pointer near UINTPTR_MAX */
+ /* Compute offset that allows CEIL to align up without wrapping */
+ /* Ensure no overflow: near_max + CACHE_LINE_ALIGN - 1 must not wrap */
+ uintptr_t near_max = UINTPTR_MAX - RTE_COMMON_TEST_BOUNDARY_TEST_OFFSET;
+ void *high_ptr = (void *)near_max;
+ uintptr_t expected_ceil = ((near_max + RTE_COMMON_TEST_CACHE_LINE_ALIGN - 1) /
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN) *
+ RTE_COMMON_TEST_CACHE_LINE_ALIGN;
+
+ result = RTE_PTR_ALIGN_CEIL(high_ptr, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "High address CEIL not aligned to %d", RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)result == expected_ceil,
+ "High address CEIL computed incorrectly: got %p, expected %p",
+ result, (void *)expected_ceil);
+ RTE_TEST_ASSERT((uintptr_t)result >= near_max,
+ "High address CEIL went backward");
+
+ /* Test 3: Type preservation with extreme alignments */
+ /* Test CEIL with PAGE_SIZE - aligns upward into buffer */
+ typed_result = (uint64_t *)test_buffer;
+ typed_result = RTE_PTR_ALIGN_CEIL(typed_result, RTE_COMMON_TEST_PAGE_SIZE);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_PAGE_SIZE == 0,
+ "CEIL type preservation failed with PAGE_SIZE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "CEIL went beyond buffer bounds");
+ /* Verify we can dereference as uint64_t* (compiler should allow this) */
+ *typed_result = 0x123456789ABCDEF0ULL;
+ RTE_TEST_ASSERT(*typed_result == 0x123456789ABCDEF0ULL,
+ "CEIL type-preserved pointer dereference failed");
+
+ /* Test FLOOR with CACHE_LINE_ALIGN - buffer is guaranteed cache-line aligned */
+ /* Use cache line alignment since buffer is only guaranteed RTE_CACHE_LINE_SIZE aligned */
+ typed_result = (uint64_t *)(test_buffer + RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ typed_result = RTE_PTR_ALIGN_FLOOR(typed_result, RTE_COMMON_TEST_CACHE_LINE_ALIGN);
+ RTE_TEST_ASSERT((uintptr_t)typed_result % RTE_COMMON_TEST_CACHE_LINE_ALIGN == 0,
+ "FLOOR type preservation failed with CACHE_LINE alignment");
+ RTE_TEST_ASSERT((uintptr_t)typed_result >= (uintptr_t)test_buffer,
+ "FLOOR went before buffer start");
+ RTE_TEST_ASSERT((uintptr_t)typed_result <
+ (uintptr_t)test_buffer + RTE_COMMON_TEST_EDGE_CASE_BUFFER_SIZE,
+ "FLOOR went beyond buffer bounds");
+ /* Safe to dereference now */
+ *typed_result = 0xDEADBEEFCAFEBABEULL;
+ RTE_TEST_ASSERT(*typed_result == 0xDEADBEEFCAFEBABEULL,
+ "FLOOR type-preserved pointer dereference failed");
+
+ return 0;
+}
+
/* this is really a sanity check */
static int
-test_macros(int __rte_unused unused_parm)
+test_macros(void)
{
#define SMALLER 0x1000U
#define BIGGER 0x2000U
@@ -37,10 +496,6 @@ test_macros(int __rte_unused unused_parm)
RTE_SWAP(smaller, bigger);
RTE_TEST_ASSERT(smaller == BIGGER && bigger == SMALLER,
"RTE_SWAP");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF), BIGGER,
- "RTE_PTR_ADD");
- RTE_TEST_ASSERT_EQUAL((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF), SMALLER,
- "RTE_PTR_SUB");
RTE_TEST_ASSERT_EQUAL(RTE_PTR_DIFF(BIGGER, SMALLER), PTR_DIFF,
"RTE_PTR_DIFF");
RTE_TEST_ASSERT_EQUAL(RTE_MAX(SMALLER, BIGGER), BIGGER,
@@ -188,19 +643,11 @@ test_align(void)
if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p)
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
- val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p);
- if (ERROR_FLOOR(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p);
-
val = RTE_ALIGN_FLOOR(i, p);
if (ERROR_FLOOR(val, i, p))
FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p);
/* align ceiling */
- val = RTE_PTR_ALIGN((uintptr_t) i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN", i, p);
-
val = RTE_ALIGN(i, p);
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN", i, p);
@@ -209,10 +656,6 @@ test_align(void)
if (ERROR_CEIL(val, i, p))
FAIL_ALIGN("RTE_ALIGN_CEIL", i, p);
- val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p);
- if (ERROR_CEIL(val, i, p))
- FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p);
-
/* by this point we know that val is aligned to p */
if (!rte_is_aligned((void*)(uintptr_t) val, p))
FAIL("rte_is_aligned");
@@ -340,18 +783,27 @@ test_fls(void)
return 0;
}
+static struct unit_test_suite common_test_suite = {
+ .suite_name = "common autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_ptr_add_sub_align),
+ TEST_CASE(test_ptr_align_edge_cases),
+ TEST_CASE(test_align),
+ TEST_CASE(test_macros),
+ TEST_CASE(test_misc),
+ TEST_CASE(test_bsf),
+ TEST_CASE(test_log2),
+ TEST_CASE(test_fls),
+ TEST_CASES_END()
+ }
+};
+
static int
test_common(void)
{
- int ret = 0;
- ret |= test_align();
- ret |= test_macros(0);
- ret |= test_misc();
- ret |= test_bsf();
- ret |= test_log2();
- ret |= test_fls();
-
- return ret;
+ return unit_test_suite_runner(&common_test_suite);
}
REGISTER_FAST_TEST(common_autotest, NOHUGE_OK, ASAN_OK, test_common);
diff --git a/doc/guides/rel_notes/release_26_03.rst b/doc/guides/rel_notes/release_26_03.rst
index 031eaa657e..dda0cec591 100644
--- a/doc/guides/rel_notes/release_26_03.rst
+++ b/doc/guides/rel_notes/release_26_03.rst
@@ -116,6 +116,19 @@ API Changes
* cfgfile: name must be less than CFG_NAME_LEN
and value must be less than CFG_VALUE_LEN.
+* **eal: Improved pointer arithmetic macros.**
+
+ * ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``, ``RTE_PTR_ALIGN_CEIL``,
+ and ``RTE_PTR_ALIGN_FLOOR`` now preserve const/volatile qualifiers and use
+ pointer arithmetic instead of integer casts to enable compiler optimizations. These
+ macros do not nest infinitely and may require intermediate variables.
+ * Passing NULL to ``RTE_PTR_ADD``, ``RTE_PTR_SUB``, ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL``, or ``RTE_PTR_ALIGN_FLOOR`` clarified as undefined behavior.
+ * Existing code passing integer types as pointer to ``RTE_PTR_ADD`` or ``RTE_PTR_SUB``
+ should use native operators (e.g. + -).
+ * Existing code passing integer types as pointer to ``RTE_PTR_ALIGN``,
+ ``RTE_PTR_ALIGN_CEIL`` or ``RTE_PTR_ALIGN_FLOOR`` should use
+ ``RTE_ALIGN``, ``RTE_ALIGN_CEIL`` or ``RTE_ALIGN_FLOOR``.
ABI Changes
-----------
diff --git a/drivers/bus/cdx/cdx_vfio.c b/drivers/bus/cdx/cdx_vfio.c
index 11fe3265d2..a1009bc0ca 100644
--- a/drivers/bus/cdx/cdx_vfio.c
+++ b/drivers/bus/cdx/cdx_vfio.c
@@ -367,9 +367,16 @@ cdx_vfio_get_region_info(int vfio_dev_fd, struct vfio_region_info **info,
static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
- size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
- void **max_va = arg;
+ size_t sz;
+ void *end_va;
+ void **max_va;
+
+ if (msl->base_va == NULL)
+ return 0;
+
+ sz = msl->len;
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
+ max_va = arg;
if (*max_va < end_va)
*max_va = end_va;
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 2ffac82e94..455db2cdec 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -109,9 +109,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->len;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index fbafc5027d..0ef05c0096 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -122,9 +122,13 @@ static int
find_max_end_va(const struct rte_memseg_list *msl, void *arg)
{
size_t sz = msl->memseg_arr.len * msl->page_sz;
- void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+ void *end_va;
void **max_va = arg;
+ if (msl->base_va == NULL)
+ return 0;
+
+ end_va = RTE_PTR_ADD(msl->base_va, sz);
if (*max_va < end_va)
*max_va = end_va;
return 0;
diff --git a/drivers/common/cnxk/roc_cpt_debug.c b/drivers/common/cnxk/roc_cpt_debug.c
index 28aedf088e..44c47a341c 100644
--- a/drivers/common/cnxk/roc_cpt_debug.c
+++ b/drivers/common/cnxk/roc_cpt_debug.c
@@ -16,8 +16,8 @@
static inline void
cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
- struct cpt_rxc_sg_s *rxc_sg;
+ const struct cpt_frag_info_s *frag_info;
+ const struct cpt_rxc_sg_s *rxc_sg;
uint32_t offset;
int i;
@@ -94,7 +94,7 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
frag_info++;
}
- rxc_sg = (struct cpt_rxc_sg_s *)frag_info;
+ rxc_sg = (const struct cpt_rxc_sg_s *)frag_info;
for (i = 0; i < cpth->w4.sctr_size; i++) {
cpt_dump(file, "CPT RXC SC SGS \t%p:", rxc_sg);
cpt_dump(file, "W0: seg1_size \t0x%x\t\tseg2_size \t0x%x\t\tseg3_size \t0x%04x",
@@ -125,9 +125,9 @@ cpt_cnxk_parse_hdr_dump(FILE *file, const struct cpt_parse_hdr_s *cpth)
static inline void
cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
{
- struct cpt_frag_info_s *frag_info;
+ const struct cpt_frag_info_s *frag_info;
uint32_t offset;
- uint64_t *slot;
+ const uint64_t *slot;
cpt_dump(file, "CPT_PARSE \t0x%p:", cpth);
@@ -178,7 +178,7 @@ cpt_cn10k_parse_hdr_dump(FILE *file, const struct cpt_cn10k_parse_hdr_s *cpth)
cpt_dump(file, "W1: frag_size2 \t0x%x", frag_info->w1.frag_size2);
cpt_dump(file, "W1: frag_size3 \t0x%x", frag_info->w1.frag_size3);
- slot = (uint64_t *)(frag_info + 1);
+ slot = (const uint64_t *)(frag_info + 1);
cpt_dump(file, "Frag Slot2: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[0]));
cpt_dump(file, "Frag Slot3: WQE ptr \t%p", (void *)plt_be_to_cpu_64(slot[1]));
}
diff --git a/drivers/common/cnxk/roc_ml.c b/drivers/common/cnxk/roc_ml.c
index 7390697b1d..e82bb58943 100644
--- a/drivers/common/cnxk/roc_ml.c
+++ b/drivers/common/cnxk/roc_ml.c
@@ -589,7 +589,9 @@ roc_ml_blk_init(struct roc_bphy *roc_bphy, struct roc_ml *roc_ml)
plt_ml_dbg(
"MLAB: Physical Address : 0x%016lx",
- 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));
plt_ml_dbg("MLAB: Virtual Address : 0x%016lx",
PLT_PTR_ADD_U64_CAST(ml->pci_dev->mem_resource[0].addr, ML_MLAB_BLK_OFFSET));
diff --git a/drivers/common/cnxk/roc_nix_bpf.c b/drivers/common/cnxk/roc_nix_bpf.c
index 98c9855a5b..5de4fc3efe 100644
--- a/drivers/common/cnxk/roc_nix_bpf.c
+++ b/drivers/common/cnxk/roc_nix_bpf.c
@@ -160,7 +160,7 @@ nix_precolor_conv_table_write(struct roc_nix *roc_nix, uint64_t val,
struct nix *nix = roc_nix_to_nix_priv(roc_nix);
int64_t *addr;
- addr = PLT_PTR_ADD(nix->base, off);
+ addr = (void *)(uintptr_t)(nix->base + off);
plt_write64(val, addr);
}
diff --git a/drivers/common/cnxk/roc_nix_inl.h b/drivers/common/cnxk/roc_nix_inl.h
index 7970ac2258..27f3f79c36 100644
--- a/drivers/common/cnxk/roc_nix_inl.h
+++ b/drivers/common/cnxk/roc_nix_inl.h
@@ -59,7 +59,7 @@ roc_nix_inl_on_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ie_on_outb_sa *
@@ -67,7 +67,7 @@ roc_nix_inl_on_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_ON_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/cnxk/roc_nix_inl_dp.h b/drivers/common/cnxk/roc_nix_inl_dp.h
index eb101db179..688d703fd1 100644
--- a/drivers/common/cnxk/roc_nix_inl_dp.h
+++ b/drivers/common/cnxk/roc_nix_inl_dp.h
@@ -49,7 +49,7 @@ roc_nix_inl_ot_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ot_ipsec_outb_sa *
@@ -57,7 +57,7 @@ roc_nix_inl_ot_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OT_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
@@ -77,7 +77,7 @@ roc_nix_inl_ow_ipsec_inb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_INB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline struct roc_ow_ipsec_outb_sa *
@@ -85,7 +85,7 @@ roc_nix_inl_ow_ipsec_outb_sa(uintptr_t base, uint64_t idx)
{
uint64_t off = idx << ROC_NIX_INL_OW_IPSEC_OUTB_SA_SZ_LOG2;
- return PLT_PTR_ADD(base, off);
+ return (void *)(base + off);
}
static inline void *
diff --git a/drivers/common/mlx5/mlx5_common_mr.c b/drivers/common/mlx5/mlx5_common_mr.c
index 8ed988dec9..aae39fdb6e 100644
--- a/drivers/common/mlx5/mlx5_common_mr.c
+++ b/drivers/common/mlx5/mlx5_common_mr.c
@@ -1447,7 +1447,7 @@ mlx5_mempool_get_extmem_cb(struct rte_mempool *mp, void *opaque,
seg = &heap[data->heap_size - 1];
msl = rte_mem_virt2memseg_list((void *)addr);
page_size = msl != NULL ? msl->page_sz : rte_mem_page_size();
- page_start = RTE_PTR_ALIGN_FLOOR(addr, page_size);
+ page_start = RTE_ALIGN_FLOOR(addr, page_size);
seg->start = page_start;
seg->end = page_start + page_size;
/* Maintain the heap order. */
diff --git a/drivers/dma/idxd/idxd_pci.c b/drivers/dma/idxd/idxd_pci.c
index 214f6f22d5..fb76a050b1 100644
--- a/drivers/dma/idxd/idxd_pci.c
+++ b/drivers/dma/idxd/idxd_pci.c
@@ -59,7 +59,7 @@ idxd_pci_dev_command(struct idxd_dmadev *idxd, enum rte_idxd_cmds command)
return err_code;
}
-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,
@@ -205,9 +205,9 @@ init_pci_device(struct rte_pci_device *dev, struct idxd_dmadev *idxd,
pci->regs = dev->mem_resource[0].addr;
version = pci->regs->version;
grp_offset = (uint16_t)pci->regs->offsets[0];
- pci->grp_regs = RTE_PTR_ADD(pci->regs, grp_offset * 0x100);
+ pci->grp_regs = RTE_PTR_ADD((volatile void *)pci->regs, grp_offset * 0x100);
wq_offset = (uint16_t)(pci->regs->offsets[0] >> 16);
- pci->wq_regs_base = RTE_PTR_ADD(pci->regs, wq_offset * 0x100);
+ pci->wq_regs_base = RTE_PTR_ADD((volatile void *)pci->regs, wq_offset * 0x100);
pci->portals = dev->mem_resource[2].addr;
pci->wq_cfg_sz = (pci->regs->wqcap >> 24) & 0x0F;
@@ -395,7 +395,10 @@ idxd_dmadev_probe_pci(struct rte_pci_driver *drv, struct rte_pci_device *dev)
/* add the queue number to each device name */
snprintf(qname, sizeof(qname), "%s-q%d", name, qid);
idxd.qid = qid;
- idxd.portal = RTE_PTR_ADD(idxd.u.pci->portals,
+ /* FIXME: cast drops volatile propagation to idxd_dmadev.portal
+ * See: https://bugs.dpdk.org/show_bug.cgi?id=1871
+ */
+ idxd.portal = RTE_PTR_ADD(RTE_PTR_UNQUAL(idxd.u.pci->portals),
qid * IDXD_PORTAL_SIZE);
if (idxd_is_wq_enabled(&idxd))
IDXD_PMD_ERR("Error, WQ %u seems enabled", qid);
diff --git a/drivers/dma/odm/odm_dmadev.c b/drivers/dma/odm/odm_dmadev.c
index a2f4ed9a8e..3b4b058427 100644
--- a/drivers/dma/odm/odm_dmadev.c
+++ b/drivers/dma/odm/odm_dmadev.c
@@ -422,7 +422,7 @@ odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
@@ -482,7 +482,7 @@ odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb
int cnt;
vq = &odm->vq[vchan];
- const uint32_t *base_addr = vq->cring_mz->addr;
+ uint32_t *base_addr = vq->cring_mz->addr;
const uint16_t cring_max_entry = vq->cring_max_entry;
cring_head = vq->cring_head;
diff --git a/drivers/event/cnxk/cn10k_worker.c b/drivers/event/cnxk/cn10k_worker.c
index 80077ec8a1..f33c3a561a 100644
--- a/drivers/event/cnxk/cn10k_worker.c
+++ b/drivers/event/cnxk/cn10k_worker.c
@@ -261,14 +261,14 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -291,10 +291,10 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -310,8 +310,8 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -322,7 +322,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -338,7 +338,7 @@ cn10k_sso_hws_new_event_lmtst(struct cn10k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/event/cnxk/cn20k_worker.c b/drivers/event/cnxk/cn20k_worker.c
index 53daf3b4b0..8c1df3dbaf 100644
--- a/drivers/event/cnxk/cn20k_worker.c
+++ b/drivers/event/cnxk/cn20k_worker.c
@@ -231,14 +231,14 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw7 = vorrq_u64(vandq_u64(vshrq_n_u64(aw7, 6), tt_mask), aw7);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 64), aw4);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 80), aw5);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 96), aw6);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 112), aw7);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 128);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ vst1q_u64((void *)(lmt_addr + 64), aw4);
+ vst1q_u64((void *)(lmt_addr + 80), aw5);
+ vst1q_u64((void *)(lmt_addr + 96), aw6);
+ vst1q_u64((void *)(lmt_addr + 112), aw7);
+ lmt_addr += 128;
} break;
case 4: {
uint64x2_t aw0, aw1, aw2, aw3;
@@ -253,10 +253,10 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw3 = vorrq_u64(vandq_u64(vshrq_n_u64(aw3, 6), tt_mask), aw3);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 32), aw2);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 48), aw3);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 64);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ vst1q_u64((void *)(lmt_addr + 32), aw2);
+ vst1q_u64((void *)(lmt_addr + 48), aw3);
+ lmt_addr += 64;
} break;
case 2: {
uint64x2_t aw0, aw1;
@@ -268,8 +268,8 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw1 = vorrq_u64(vandq_u64(vshrq_n_u64(aw1, 6), tt_mask), aw1);
vst1q_u64((void *)lmt_addr, aw0);
- vst1q_u64((void *)PLT_PTR_ADD(lmt_addr, 16), aw1);
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 32);
+ vst1q_u64((void *)(lmt_addr + 16), aw1);
+ lmt_addr += 32;
} break;
case 1: {
__uint128_t aw0;
@@ -280,7 +280,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
} break;
}
ev += parts;
@@ -296,7 +296,7 @@ cn20k_sso_hws_new_event_lmtst(struct cn20k_sso_hws *ws, uint8_t queue_id,
aw0 |= ev[0].event & (BIT_ULL(32) - 1);
aw0 |= (uint64_t)ev[0].sched_type << 32;
*((__uint128_t *)lmt_addr) = aw0;
- lmt_addr = (uintptr_t)PLT_PTR_ADD(lmt_addr, 16);
+ lmt_addr += 16;
}
#endif
diff --git a/drivers/mempool/bucket/rte_mempool_bucket.c b/drivers/mempool/bucket/rte_mempool_bucket.c
index c0b480bfc7..6fee10176b 100644
--- a/drivers/mempool/bucket/rte_mempool_bucket.c
+++ b/drivers/mempool/bucket/rte_mempool_bucket.c
@@ -376,8 +376,8 @@ count_underfilled_buckets(struct rte_mempool *mp,
uintptr_t align;
uint8_t *iter;
- align = (uintptr_t)RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz) -
- (uintptr_t)memhdr->addr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(memhdr->addr, bucket_page_sz),
+ memhdr->addr);
for (iter = (uint8_t *)memhdr->addr + align;
iter < (uint8_t *)memhdr->addr + memhdr->len;
@@ -602,8 +602,7 @@ bucket_populate(struct rte_mempool *mp, unsigned int max_objs,
return -EINVAL;
bucket_page_sz = rte_align32pow2(bd->bucket_mem_size);
- align = RTE_PTR_ALIGN_CEIL((uintptr_t)vaddr, bucket_page_sz) -
- (uintptr_t)vaddr;
+ align = RTE_PTR_DIFF(RTE_PTR_ALIGN_CEIL(vaddr, bucket_page_sz), vaddr);
bucket_header_sz = bd->header_size - mp->header_size;
if (iova != RTE_BAD_IOVA)
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
index e9d45f24c4..a5d112d52d 100644
--- a/drivers/net/cxgbe/sge.c
+++ b/drivers/net/cxgbe/sge.c
@@ -591,7 +591,7 @@ static void write_sgl(struct rte_mbuf *mbuf, struct sge_txq *q,
memcpy(sgl->sge, buf, part0);
part1 = RTE_PTR_DIFF((u8 *)end, (u8 *)q->stat);
rte_memcpy(q->desc, RTE_PTR_ADD((u8 *)buf, part0), part1);
- end = RTE_PTR_ADD((void *)q->desc, part1);
+ end = RTE_PTR_ADD(q->desc, part1);
}
if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*(u64 *)end = 0;
@@ -1297,7 +1297,7 @@ static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
from = RTE_PTR_ADD(from, left);
left = len - left;
rte_memcpy((void *)q->desc, from, left);
- *to = RTE_PTR_ADD((void *)q->desc, left);
+ *to = RTE_PTR_ADD(q->desc, left);
}
}
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ea4afbc75d..da23b271d5 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2379,7 +2379,14 @@ static void *pci_bar_addr(struct rte_pci_device *dev, uint32_t bar)
{
const struct rte_mem_resource *res = &dev->mem_resource[bar];
size_t offset = res->phys_addr % rte_mem_page_size();
- void *vaddr = RTE_PTR_ADD(res->addr, offset);
+ void *vaddr;
+
+ if (res->addr == NULL) {
+ PMD_INIT_LOG_LINE(ERR, "PCI BAR [%u] address is NULL", bar);
+ return NULL;
+ }
+
+ vaddr = RTE_PTR_ADD(res->addr, offset);
PMD_INIT_LOG_LINE(INFO, "PCI BAR [%u]: phys_addr=0x%" PRIx64 ", addr=%p, offset=0x%zx, adjusted_addr=%p",
bar, res->phys_addr, res->addr, offset, vaddr);
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 0db2e55bef..26e40e5218 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -114,7 +114,8 @@ txq_uar_uninit_secondary(struct txq *txq)
void *addr;
addr = ppriv->uar_table[txq->stats.idx];
- munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ if (addr != NULL)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
}
/**
diff --git a/lib/eal/common/eal_common_fbarray.c b/lib/eal/common/eal_common_fbarray.c
index 8bdcefb717..526ba9f2eb 100644
--- a/lib/eal/common/eal_common_fbarray.c
+++ b/lib/eal/common/eal_common_fbarray.c
@@ -10,6 +10,7 @@
#include <unistd.h>
#include <rte_common.h>
+#include <rte_debug.h>
#include <rte_eal_paging.h>
#include <rte_errno.h>
#include <rte_log.h>
@@ -1048,7 +1049,7 @@ void *
rte_fbarray_get(const struct rte_fbarray *arr, unsigned int idx)
{
void *ret = NULL;
- if (arr == NULL) {
+ if (arr == NULL || arr->data == NULL) {
rte_errno = EINVAL;
return NULL;
}
diff --git a/lib/eal/common/eal_common_memory.c b/lib/eal/common/eal_common_memory.c
index dccf9406c5..206c99695a 100644
--- a/lib/eal/common/eal_common_memory.c
+++ b/lib/eal/common/eal_common_memory.c
@@ -309,6 +309,9 @@ virt2memseg(const void *addr, const struct rte_memseg_list *msl)
/* a memseg list was specified, check if it's the right one */
start = msl->base_va;
+ if (start == NULL)
+ return NULL;
+
end = RTE_PTR_ADD(start, msl->len);
if (addr < start || addr >= end)
@@ -332,6 +335,8 @@ virt2memseg_list(const void *addr)
msl = &mcfg->memsegs[msl_idx];
start = msl->base_va;
+ if (start == NULL)
+ continue;
end = RTE_PTR_ADD(start, msl->len);
if (addr >= start && addr < end)
break;
@@ -680,10 +685,16 @@ RTE_EXPORT_SYMBOL(rte_mem_lock_page)
int
rte_mem_lock_page(const void *virt)
{
- uintptr_t virtual = (uintptr_t)virt;
size_t page_size = rte_mem_page_size();
- uintptr_t aligned = RTE_PTR_ALIGN_FLOOR(virtual, page_size);
- return rte_mem_lock((void *)aligned, page_size);
+ const void *aligned;
+
+ if (virt == NULL) {
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ aligned = RTE_PTR_ALIGN_FLOOR(virt, page_size);
+ return rte_mem_lock(aligned, page_size);
}
RTE_EXPORT_SYMBOL(rte_memseg_contig_walk_thread_unsafe)
@@ -1448,7 +1459,7 @@ handle_eal_memseg_info_request(const char *cmd __rte_unused,
ms_iova = ms->iova;
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
ms_size = ms->len;
hugepage_size = ms->hugepage_sz;
ms_socket_id = ms->socket_id;
@@ -1520,7 +1531,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
rte_tel_data_start_dict(d);
@@ -1531,8 +1542,7 @@ handle_eal_element_list_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if ((uint64_t)elem_start_addr >= ms_start_addr &&
(uint64_t)elem_end_addr <= ms_end_addr)
@@ -1554,7 +1564,8 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
struct rte_mem_config *mcfg;
struct rte_memseg_list *msl;
const struct rte_memseg *ms;
- struct malloc_elem *elem;
+ /* volatile placement consistent with malloc_heap pointers */
+ struct malloc_elem *volatile elem;
struct malloc_heap *heap;
struct rte_tel_data *c;
uint64_t ms_start_addr, ms_end_addr;
@@ -1598,7 +1609,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
}
ms_start_addr = ms->addr_64;
- ms_end_addr = (uint64_t)RTE_PTR_ADD(ms_start_addr, ms->len);
+ ms_end_addr = ms_start_addr + ms->len;
rte_mcfg_mem_read_unlock();
@@ -1610,8 +1621,7 @@ handle_eal_element_info_request(const char *cmd __rte_unused,
elem = heap->first;
while (elem) {
elem_start_addr = (uint64_t)elem;
- elem_end_addr =
- (uint64_t)RTE_PTR_ADD(elem_start_addr, elem->size);
+ elem_end_addr = elem_start_addr + elem->size;
if (elem_start_addr < ms_start_addr ||
elem_end_addr > ms_end_addr) {
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index aad676a004..2e732ff8ee 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -1664,8 +1664,7 @@ eal_parse_base_virtaddr(const char *arg)
* it can align to 2MB for x86. So this alignment can also be used
* on x86 and other architectures.
*/
- internal_conf->base_virtaddr =
- RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+ internal_conf->base_virtaddr = RTE_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
return 0;
}
diff --git a/lib/eal/common/malloc_elem.h b/lib/eal/common/malloc_elem.h
index c7ff6718f8..babaead7de 100644
--- a/lib/eal/common/malloc_elem.h
+++ b/lib/eal/common/malloc_elem.h
@@ -79,9 +79,11 @@ static const unsigned int MALLOC_ELEM_TRAILER_LEN = RTE_CACHE_LINE_SIZE;
#define MALLOC_TRAILER_COOKIE 0xadd2e55badbadbadULL /**< Trailer cookie.*/
/* define macros to make referencing the header and trailer cookies easier */
-#define MALLOC_ELEM_TRAILER(elem) (*((uint64_t*)RTE_PTR_ADD(elem, \
- elem->size - MALLOC_ELEM_TRAILER_LEN)))
-#define MALLOC_ELEM_HEADER(elem) (elem->header_cookie)
+#define MALLOC_ELEM_TRAILER(elem) \
+ /* typeof preserves qualifiers (const/volatile) of elem */ \
+ (*(typeof((elem)->header_cookie) *)RTE_PTR_ADD(elem, \
+ (elem)->size - MALLOC_ELEM_TRAILER_LEN))
+#define MALLOC_ELEM_HEADER(elem) ((elem)->header_cookie)
static inline void
set_header(struct malloc_elem *elem)
@@ -306,13 +308,31 @@ old_malloc_size(struct malloc_elem *elem)
static inline struct malloc_elem *
malloc_elem_from_data(const void *data)
{
+ struct malloc_elem *result;
+
if (data == NULL)
return NULL;
- struct malloc_elem *elem = RTE_PTR_SUB(data, MALLOC_ELEM_HEADER_LEN);
- if (!malloc_elem_cookies_ok(elem))
- return NULL;
- return elem->state != ELEM_PAD ? elem: RTE_PTR_SUB(elem, elem->pad);
+ /* The allocator returns a pointer in the middle of an allocation pool.
+ * GCC's interprocedural analysis can't trace this and warns about
+ * out-of-bounds access when we do backwards pointer arithmetic to
+ * find the malloc_elem header.
+ */
+ __rte_diagnostic_push
+ __rte_diagnostic_ignored_array_bounds
+ {
+ struct malloc_elem *elem =
+ RTE_PTR_SUB(RTE_PTR_UNQUAL(data), MALLOC_ELEM_HEADER_LEN);
+
+ if (!malloc_elem_cookies_ok(elem))
+ result = NULL;
+ else
+ result = elem->state != ELEM_PAD ? elem :
+ RTE_PTR_SUB(elem, elem->pad);
+ }
+ __rte_diagnostic_pop
+
+ return result;
}
/*
diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c
index 6d3d46a390..49a89fe2fb 100644
--- a/lib/eal/freebsd/eal_memory.c
+++ b/lib/eal/freebsd/eal_memory.c
@@ -178,6 +178,10 @@ rte_eal_hugepage_init(void)
"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
return -1;
}
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list %d", msl_idx);
+ return -1;
+ }
arr = &msl->memseg_arr;
seg = rte_fbarray_get(arr, ms_idx);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 573bf4f2ce..86b0a75bb3 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -103,6 +103,34 @@ extern "C" {
__GNUC_PATCHLEVEL__)
#endif
+/*
+ * Type inference for use in macros.
+ */
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define __rte_auto_type auto
+#elif defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_auto_type __auto_type
+#endif
+
+/*
+ * Helper macro for array decay in pointer arithmetic macros.
+ * Example: char arr[10]; RTE_PTR_ADD(arr, 5) needs arr to decay to char*.
+ *
+ * GCC/Clang in C mode need "+ 0" to force arrays to decay to pointers.
+ * Not needed for C++ (automatic decay) or MSVC (ternary checks both branches).
+ *
+ * Note: This must be an object-like macro (not function-like) because it gets
+ * used with nested macro expansion (e.g., RTE_PTR_ALIGN_FLOOR(RTE_PTR_ADD(...))).
+ * A function-like macro would wrap the argument in parentheses, causing _Pragma
+ * directives from nested statement expressions to appear in invalid contexts.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC) && !defined(__cplusplus)
+#define __rte_ptr_arith_add_zero + 0
+#else
+#define __rte_ptr_arith_add_zero
+#endif
+
/**
* Force type alignment
*
@@ -210,6 +238,16 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_diagnostic_ignored_wcast_qual
#endif
+/**
+ * Macro to disable compiler warnings about invalid array bounds access.
+ */
+#if !defined(RTE_TOOLCHAIN_MSVC)
+#define __rte_diagnostic_ignored_array_bounds \
+ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
+#else
+#define __rte_diagnostic_ignored_array_bounds
+#endif
+
/**
* Mark a function or variable to a weak reference.
*/
@@ -549,14 +587,72 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/*********** Macros for pointer arithmetic ********/
/**
- * add a byte-value offset to a pointer
+ * Add a byte-value offset to a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to add
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ADD(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_add = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_add_res = \
+ (1 ? (void *)((char *)__rte_ptr_add + (x)) : __rte_ptr_add); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_add_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_ADD(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) + (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
- * subtract a byte-value offset from a pointer
+ * Subtract a byte-value offset from a pointer.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param x
+ * Byte offset to subtract
+ * @return
+ * void* (or const void* / volatile void* / const volatile void* preserving qualifiers).
+ * Returning void* prevents the compiler from making alignment assumptions based
+ * on the pointer type, which is important when doing byte-offset arithmetic that
+ * may cross struct boundaries or result in unaligned pointers.
*/
-#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_SUB(ptr, x) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_sub = (ptr) __rte_ptr_arith_add_zero; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (2) Calculate result, preserving const/volatile via ternary */ \
+ __rte_auto_type __rte_ptr_sub_res = \
+ (1 ? (void *)((char *)__rte_ptr_sub - (x)) : __rte_ptr_sub); \
+ __rte_diagnostic_pop \
+ /* (3) Return the result */ \
+ __rte_ptr_sub_res; \
+}))
+#else
+/* MSVC fallback (ternary preserves const, no statement exprs) */
+#define RTE_PTR_SUB(ptr, x) \
+ (1 ? (void *)((char *)((ptr) __rte_ptr_arith_add_zero) - (x)) : \
+ ((ptr) __rte_ptr_arith_add_zero))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
@@ -602,13 +698,40 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no higher than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer down to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no higher than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
- ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t)(ptr), align))
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_floor = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute misalignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_floor_misalign = (uintptr_t)__rte_ptr_floor & ((align) - 1); \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ __rte_auto_type __rte_ptr_floor_res = \
+ (typeof(__rte_ptr_floor))((char *)__rte_ptr_floor - __rte_ptr_floor_misalign); \
+ __rte_diagnostic_pop \
+ __rte_ptr_floor_res; \
+}))
+#else
+#define RTE_PTR_ALIGN_FLOOR(ptr, align) \
+ ((typeof(ptr))RTE_ALIGN_FLOOR((uintptr_t) ((ptr) __rte_ptr_arith_add_zero), align))
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
@@ -620,13 +743,43 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
(typeof(val))((val) & (~((typeof(val))((align) - 1))))
/**
- * Macro to align a pointer to a given power-of-two. The resultant
- * pointer will be a pointer of the same type as the first parameter, and
- * point to an address no lower than the first parameter. Second parameter
- * must be a power-of-two value.
+ * Macro to align a pointer to a given power-of-two.
+ *
+ * Aligns the pointer up to the specified alignment boundary.
+ *
+ * @param ptr
+ * The pointer (must be non-NULL)
+ * @param align
+ * Alignment boundary (must be a power-of-two value)
+ * @return
+ * Aligned pointer of the same type as ptr, pointing to an address no lower than ptr.
+ * Returns pointer of same type as input, preserving const/volatile qualifiers.
+ * Since alignment operations guarantee proper alignment, the return type matches
+ * the input type.
*/
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define RTE_PTR_ALIGN_CEIL(ptr, align) \
+(__extension__ ({ \
+ /* (1) Force array decay and ensure single evaluation */ \
+ __rte_auto_type __rte_ptr_ceil = (ptr) __rte_ptr_arith_add_zero; \
+ /* (2) Compute alignment as integer, but adjust pointer using pointer arithmetic */ \
+ size_t __rte_ptr_ceil_align_m1 = (align) - 1; \
+ uintptr_t __rte_ptr_ceil_aligned = ((uintptr_t)__rte_ptr_ceil + __rte_ptr_ceil_align_m1) \
+ & ~__rte_ptr_ceil_align_m1; \
+ size_t __rte_ptr_ceil_offset = __rte_ptr_ceil_aligned - (uintptr_t)__rte_ptr_ceil; \
+ __rte_diagnostic_push \
+ __rte_diagnostic_ignored_wcast_qual \
+ /* (3) Return the aligned result, cast to preserve input type. We avoid RTE_PTR_SUB */ \
+ /* to skip the void* cast which may defeat compiler alignment optimizations. */ \
+ __rte_auto_type __rte_ptr_ceil_res = \
+ (typeof(__rte_ptr_ceil))((char *)__rte_ptr_ceil + __rte_ptr_ceil_offset); \
+ __rte_diagnostic_pop \
+ __rte_ptr_ceil_res; \
+}))
+#else
#define RTE_PTR_ALIGN_CEIL(ptr, align) \
RTE_PTR_ALIGN_FLOOR((typeof(ptr))RTE_PTR_ADD(ptr, (align) - 1), align)
+#endif
/**
* Macro to align a value to a given power-of-two. The resultant value
diff --git a/lib/eal/linux/eal_memalloc.c b/lib/eal/linux/eal_memalloc.c
index 4dee224ac5..bb040b9f8e 100644
--- a/lib/eal/linux/eal_memalloc.c
+++ b/lib/eal/linux/eal_memalloc.c
@@ -842,6 +842,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va,
cur_idx * page_sz);
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index bf783e3c76..e00fa61be2 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -771,6 +771,13 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
return -1;
}
memseg_len = (size_t)page_sz;
+
+ if (msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ close(fd);
+ return -1;
+ }
+
addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
/* we know this address is already mmapped by memseg list, so
diff --git a/lib/eal/windows/eal_memalloc.c b/lib/eal/windows/eal_memalloc.c
index 5db5a474cc..6432caccd3 100644
--- a/lib/eal/windows/eal_memalloc.c
+++ b/lib/eal/windows/eal_memalloc.c
@@ -230,6 +230,12 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
void *map_addr;
cur = rte_fbarray_get(&cur_msl->memseg_arr, cur_idx);
+
+ if (cur_msl->base_va == NULL) {
+ EAL_LOG(ERR, "Base VA is NULL for memseg list");
+ goto out;
+ }
+
map_addr = RTE_PTR_ADD(cur_msl->base_va, cur_idx * page_sz);
if (alloc_seg(cur, map_addr, wa->socket, wa->hi)) {
diff --git a/lib/graph/rte_graph.h b/lib/graph/rte_graph.h
index 7e433f4661..d8ac0011e4 100644
--- a/lib/graph/rte_graph.h
+++ b/lib/graph/rte_graph.h
@@ -407,9 +407,9 @@ void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all);
/** Macro to browse rte_node object after the graph creation */
#define rte_graph_foreach_node(count, off, graph, node) \
for (count = 0, off = graph->nodes_start, \
- node = RTE_PTR_ADD(graph, off); \
+ node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off); \
count < graph->nb_nodes; \
- off = node->next, node = RTE_PTR_ADD(graph, off), count++)
+ off = node->next, node = RTE_PTR_ADD(RTE_PTR_UNQUAL(graph), off), count++)
/**
* Get node object with in graph from id.
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index f8d6762dbc..64c57806d7 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -104,6 +104,9 @@ latencystats_collect(uint64_t values[])
unsigned int i, scale;
const uint64_t *stats;
+ if (glob_stats == NULL)
+ return;
+
for (i = 0; i < NUM_LATENCY_STATS; i++) {
stats = RTE_PTR_ADD(glob_stats, lat_stats_strings[i].offset);
scale = lat_stats_strings[i].scale;
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 0d931c7a15..46d3439f8a 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -193,6 +193,8 @@ __rte_pktmbuf_init_extmem(struct rte_mempool *mp,
RTE_ASSERT(ctx->ext < ctx->ext_num);
RTE_ASSERT(ctx->off + ext_mem->elt_size <= ext_mem->buf_len);
+ RTE_ASSERT(ext_mem->buf_ptr != NULL);
+ __rte_assume(ext_mem->buf_ptr != NULL);
m->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);
rte_mbuf_iova_set(m, ext_mem->buf_iova == RTE_BAD_IOVA ? RTE_BAD_IOVA :
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 2004391f57..29a147eeb9 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -217,6 +217,8 @@ rte_mbuf_data_iova_default(const struct rte_mbuf *mb)
static inline struct rte_mbuf *
rte_mbuf_from_indirect(struct rte_mbuf *mi)
{
+ RTE_ASSERT(mi != NULL);
+ __rte_assume(mi != NULL);
return (struct rte_mbuf *)RTE_PTR_SUB(mi->buf_addr, sizeof(*mi) + mi->priv_size);
}
@@ -289,6 +291,8 @@ rte_mbuf_to_baddr(struct rte_mbuf *md)
static inline void *
rte_mbuf_to_priv(struct rte_mbuf *m)
{
+ RTE_ASSERT(m != NULL);
+ __rte_assume(m != NULL);
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
diff --git a/lib/member/rte_xxh64_avx512.h b/lib/member/rte_xxh64_avx512.h
index 58f896ebb8..774b26d8df 100644
--- a/lib/member/rte_xxh64_avx512.h
+++ b/lib/member/rte_xxh64_avx512.h
@@ -58,7 +58,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
_mm512_set1_epi64(key_len));
while (remaining >= 8) {
- input = _mm512_set1_epi64(*(uint64_t *)RTE_PTR_ADD(key, offset));
+ input = _mm512_set1_epi64(*(const uint64_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
xxh64_round_avx512(_mm512_setzero_si512(), input));
v_hash = _mm512_madd52lo_epu64(_mm512_set1_epi64(PRIME64_4),
@@ -71,7 +71,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
if (remaining >= 4) {
input = _mm512_set1_epi64
- (*(uint32_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint32_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_1)));
@@ -86,7 +86,7 @@ rte_xxh64_sketch_avx512(const void *key, uint32_t key_len,
while (remaining != 0) {
input = _mm512_set1_epi64
- (*(uint8_t *)RTE_PTR_ADD(key, offset));
+ (*(const uint8_t *)RTE_PTR_ADD(key, offset));
v_hash = _mm512_xor_epi64(v_hash,
_mm512_mullo_epi64(input,
_mm512_set1_epi64(PRIME64_5)));
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index 1144dca58a..2c865035a6 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -376,6 +376,8 @@ struct __rte_cache_aligned rte_mempool {
static inline struct rte_mempool_objhdr *
rte_mempool_get_header(void *obj)
{
+ RTE_ASSERT(obj != NULL);
+ __rte_assume(obj != NULL);
return (struct rte_mempool_objhdr *)RTE_PTR_SUB(obj,
sizeof(struct rte_mempool_objhdr));
}
@@ -399,6 +401,8 @@ static inline struct rte_mempool *rte_mempool_from_obj(void *obj)
static inline struct rte_mempool_objtlr *rte_mempool_get_trailer(void *obj)
{
struct rte_mempool *mp = rte_mempool_from_obj(obj);
+ RTE_ASSERT(mp != NULL);
+ __rte_assume(mp != NULL);
return (struct rte_mempool_objtlr *)RTE_PTR_ADD(obj, mp->elt_size);
}
@@ -1845,6 +1849,8 @@ static inline rte_iova_t
rte_mempool_virt2iova(const void *elt)
{
const struct rte_mempool_objhdr *hdr;
+ RTE_ASSERT(elt != NULL);
+ __rte_assume(elt != NULL);
hdr = (const struct rte_mempool_objhdr *)RTE_PTR_SUB(elt,
sizeof(*hdr));
return hdr->iova;
diff --git a/lib/pdcp/pdcp_entity.h b/lib/pdcp/pdcp_entity.h
index f854192e98..7a2c41dd56 100644
--- a/lib/pdcp/pdcp_entity.h
+++ b/lib/pdcp/pdcp_entity.h
@@ -198,17 +198,19 @@ struct entity_priv_ul_part {
static inline struct entity_priv *
entity_priv_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity), sizeof(struct rte_pdcp_entity));
}
static inline struct entity_priv_dl_part *
entity_dl_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline struct entity_priv_ul_part *
entity_ul_part_get(const struct rte_pdcp_entity *entity) {
- return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
+ return RTE_PTR_ADD(RTE_PTR_UNQUAL(entity),
+ sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv));
}
static inline int
diff --git a/lib/vhost/vhost_user.c b/lib/vhost/vhost_user.c
index 4bfb13fb98..a9ab6487f2 100644
--- a/lib/vhost/vhost_user.c
+++ b/lib/vhost/vhost_user.c
@@ -824,9 +824,16 @@ void
mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t pagesz)
{
#ifdef MADV_DONTDUMP
- void *start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
- uintptr_t end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
- size_t len = end - (uintptr_t)start;
+ void *start;
+ uintptr_t end;
+ size_t len;
+
+ if (ptr == NULL)
+ return;
+
+ start = RTE_PTR_ALIGN_FLOOR(ptr, pagesz);
+ end = RTE_ALIGN_CEIL((uintptr_t)ptr + size, pagesz);
+ len = end - (uintptr_t)start;
if (madvise(start, len, enable ? MADV_DODUMP : MADV_DONTDUMP) == -1) {
VHOST_CONFIG_LOG(dev->ifname, INFO,
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 60+ messages in thread
end of thread, other threads:[~2026-02-07 1:45 UTC | newest]
Thread overview: 60+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-14 16:07 [PATCH v6] eal: RTE_PTR_ADD/SUB char* for compiler optimizations scott.k.mitch1
2026-01-14 21:56 ` [PATCH v7] " scott.k.mitch1
2026-01-16 11:39 ` Morten Brørup
2026-01-16 22:38 ` Scott Mitchell
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
2026-01-17 2:44 ` Stephen Hemminger
2026-01-17 21:07 ` Scott Mitchell
2026-01-17 21:03 ` [PATCH v9] " scott.k.mitch1
2026-01-18 6:12 ` Stephen Hemminger
2026-01-23 16:20 ` Scott Mitchell
2026-01-20 12:59 ` Morten Brørup
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2026-01-24 7:58 ` Morten Brørup
2026-01-24 8:59 ` Scott Mitchell
2026-01-24 22:59 ` Scott Mitchell
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-25 11:11 ` scott.k.mitch1
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
2026-01-25 22:24 ` Scott Mitchell
2026-01-26 8:19 ` Morten Brørup
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
2026-01-26 14:35 ` Morten Brørup
2026-01-26 21:29 ` Scott Mitchell
2026-01-27 5:11 ` Scott Mitchell
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 11:16 ` Mattias Rönnblom
2026-01-27 14:07 ` Stephen Hemminger
2026-01-27 5:29 ` [PATCH v16 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-03 8:24 ` Morten Brørup
2026-02-03 9:48 ` David Marchand
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-03 9:08 ` Morten Brørup
2026-02-03 16:24 ` Scott Mitchell
2026-02-03 9:51 ` David Marchand
2026-02-03 16:25 ` Scott Mitchell
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
2026-02-04 5:20 ` Scott Mitchell
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
2026-02-04 22:47 ` Morten Brørup
2026-02-05 6:53 ` Scott Mitchell
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
2026-02-05 7:50 ` Morten Brørup
2026-02-06 1:04 ` Scott Mitchell
2026-02-06 1:01 ` [PATCH v22] " scott.k.mitch1
2026-02-06 4:28 ` [PATCH v23] " scott.k.mitch1
2026-02-06 16:09 ` Stephen Hemminger
2026-02-07 1:45 ` [PATCH v24] " scott.k.mitch1
2026-01-27 20:28 ` [REVIEW] " Stephen Hemminger
2026-02-02 5:17 ` Scott Mitchell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox