On Tue, Oct 1, 2024 at 6:39 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
> diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
> index eec0400dad..595cadd5b8 100644
> --- a/lib/eal/include/rte_common.h
> +++ b/lib/eal/include/rte_common.h
> @@ -228,6 +228,40 @@ typedef uint16_t unaligned_uint16_t;
> #define __rte_alloc_size(...)
> #endif
>
> +/**
> + * Tells the compiler that the function returns a value that points to
> + * memory aligned by a function argument.
> + *
> + * Note: not enabled on Clang because it warns if align argument is zero.
> + */
> +#if defined(RTE_CC_GCC)
> +#define __rte_alloc_align(argno) __attribute__((alloc_align(argno)))
> +#else
> +#define __rte_alloc_align(argno)
> +#endif
> +
> +/**
> + * Tells the compiler this is a function like malloc and that the pointer
> + * returned cannot alias any other pointer (ie new memory).
> + */
> +#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
> +#define __rte_malloc __attribute__((malloc))
> +#else
> +#define __rte_malloc
> +#endif
> +
> +/**
> + * With recent GCC versions also able to track that proper
> + * dealloctor function is used for this pointer.
deallocator*
> + */
> +#if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 110000)
> +#define __rte_dealloc(dealloc, argno) __attribute__((malloc(dealloc, argno)))
> +#define __rte_dealloc_free __rte_dealloc(rte_free, 1)
__rte_dealloc_free should not be in rte_common.h but in rte_malloc.h.
> +#else
> +#define __rte_dealloc(dealloc, argno)
> +#define __rte_dealloc_free
> +#endif
> +
> #define RTE_PRIORITY_LOG 101
> #define RTE_PRIORITY_BUS 110
> #define RTE_PRIORITY_CLASS 120
> diff --git a/lib/eal/include/rte_malloc.h b/lib/eal/include/rte_malloc.h
> index 1f91e7bdde..9261605939 100644
> --- a/lib/eal/include/rte_malloc.h
> +++ b/lib/eal/include/rte_malloc.h
> @@ -31,6 +31,22 @@ struct rte_malloc_socket_stats {
> size_t heap_allocsz_bytes; /**< Total allocated bytes on heap */
> };
>
> +
Nit: no need for extra line.
> +/**
> + * Frees the memory space pointed to by the provided pointer.
> + *
> + * This pointer must have been returned by a previous call to
> + * rte_malloc(), rte_zmalloc(), rte_calloc() or rte_realloc(). The behaviour of
> + * rte_free() is undefined if the pointer does not match this requirement.
> + *
@@ -55,6 +55,14 @@ New Features
Also, make sure to start the actual text at the margin.
=======================================================
+* **Hardened rte_malloc and related functions.**
+
+ * Added function attributes to ``rte_malloc`` and similar functions
+ that can catch some obvious bugs at compile time (with GCC 11.0 or later).
+ Examples: calling ``free()`` on pointer that was allocated with ``rte_malloc``
+ (and vice versa); freeing the same pointer twice in the same routine;
+ freeing an object that was not created by allocation; etc.
+
Removed Items
-------------
@@ -228,6 +228,40 @@ typedef uint16_t unaligned_uint16_t;
#define __rte_alloc_size(...)
#endif
+/**
+ * Tells the compiler that the function returns a value that points to
+ * memory aligned by a function argument.
+ *
+ * Note: not enabled on Clang because it warns if align argument is zero.
+ */
+#if defined(RTE_CC_GCC)
+#define __rte_alloc_align(argno) __attribute__((alloc_align(argno)))
+#else
+#define __rte_alloc_align(argno)
+#endif
+
+/**
+ * Tells the compiler this is a function like malloc and that the pointer
+ * returned cannot alias any other pointer (ie new memory).
+ */
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+#define __rte_malloc __attribute__((malloc))
+#else
+#define __rte_malloc
+#endif
+
+/**
+ * With recent GCC versions also able to track that proper
+ * dealloctor function is used for this pointer.
+ */
+#if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 110000)
+#define __rte_dealloc(dealloc, argno) __attribute__((malloc(dealloc, argno)))
+#define __rte_dealloc_free __rte_dealloc(rte_free, 1)
+#else
+#define __rte_dealloc(dealloc, argno)
+#define __rte_dealloc_free
+#endif
+
#define RTE_PRIORITY_LOG 101
#define RTE_PRIORITY_BUS 110
#define RTE_PRIORITY_CLASS 120
@@ -31,6 +31,22 @@ struct rte_malloc_socket_stats {
size_t heap_allocsz_bytes; /**< Total allocated bytes on heap */
};
+
+/**
+ * Frees the memory space pointed to by the provided pointer.
+ *
+ * This pointer must have been returned by a previous call to
+ * rte_malloc(), rte_zmalloc(), rte_calloc() or rte_realloc(). The behaviour of
+ * rte_free() is undefined if the pointer does not match this requirement.
+ *
+ * If the pointer is NULL, the function does nothing.
+ *
+ * @param ptr
+ * The pointer to memory to be freed.
+ */
+void
+rte_free(void *ptr);
+
/**
* This function allocates memory from the huge-page area of memory. The memory
* is not cleared. In NUMA systems, the memory allocated resides on the same
@@ -54,7 +70,8 @@ struct rte_malloc_socket_stats {
*/
void *
rte_malloc(const char *type, size_t size, unsigned align)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* Allocate zeroed memory from the heap.
@@ -81,7 +98,8 @@ rte_malloc(const char *type, size_t size, unsigned align)
*/
void *
rte_zmalloc(const char *type, size_t size, unsigned align)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* Replacement function for calloc(), using huge-page memory. Memory area is
@@ -108,7 +126,8 @@ rte_zmalloc(const char *type, size_t size, unsigned align)
*/
void *
rte_calloc(const char *type, size_t num, size_t size, unsigned align)
- __rte_alloc_size(2, 3);
+ __rte_alloc_size(2, 3) __rte_alloc_align(4)
+ __rte_malloc __rte_dealloc_free;
/**
* Replacement function for realloc(), using huge-page memory. Reserved area
@@ -132,7 +151,8 @@ rte_calloc(const char *type, size_t num, size_t size, unsigned align)
*/
void *
rte_realloc(void *ptr, size_t size, unsigned int align)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* Replacement function for realloc(), using huge-page memory. Reserved area
@@ -158,7 +178,8 @@ rte_realloc(void *ptr, size_t size, unsigned int align)
*/
void *
rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* This function allocates memory from the huge-page area of memory. The memory
@@ -185,7 +206,8 @@ rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)
*/
void *
rte_malloc_socket(const char *type, size_t size, unsigned align, int socket)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* Allocate zeroed memory from the heap.
@@ -214,7 +236,8 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket)
*/
void *
rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket)
- __rte_alloc_size(2);
+ __rte_alloc_size(2) __rte_alloc_align(3)
+ __rte_malloc __rte_dealloc_free;
/**
* Replacement function for calloc(), using huge-page memory. Memory area is
@@ -243,22 +266,8 @@ rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket)
*/
void *
rte_calloc_socket(const char *type, size_t num, size_t size, unsigned align, int socket)
- __rte_alloc_size(2, 3);
-
-/**
- * Frees the memory space pointed to by the provided pointer.
- *
- * This pointer must have been returned by a previous call to
- * rte_malloc(), rte_zmalloc(), rte_calloc() or rte_realloc(). The behaviour of
- * rte_free() is undefined if the pointer does not match this requirement.
- *
- * If the pointer is NULL, the function does nothing.
- *
- * @param ptr
- * The pointer to memory to be freed.
- */
-void
-rte_free(void *ptr);
+ __rte_alloc_size(2, 3) __rte_alloc_align(4)
+ __rte_malloc __rte_dealloc_free;
/**
* If malloc debug is enabled, check a memory block for header