Skip to content

Commit 80da7ef

Browse files
shemmingerdavid-marchand
authored andcommitted
eal: annotate allocation functions
The allocation functions take a alignment argument that can be useful to hint the compiler optimizer. This is supported by GCC and Clang but only useful with GCC because Clang gives warning if alignment is 0. Newer versions of GCC have a malloc attribute that can be used to find mismatches between allocation and free; the typical problem caught is a pointer allocated with rte_malloc() that is then incorrectly freed using free(). The name of the DPDK wrapper macros for these attributes are chosen to be similar to what GLIBC is using in cdefs.h. Note: The rte_free function prototype was moved ahead of the allocation functions since the dealloc attribute now refers to it. Signed-off-by: Stephen Hemminger <[email protected]> Reviewed-by: Morten Brørup <[email protected]> Acked-by: Chengwen Feng <[email protected]> Acked-by: Anatoly Burakov <[email protected]> Acked-by: Wathsala Vithanage <[email protected]> Acked-by: Konstantin Ananyev <[email protected]>
1 parent ae67f7d commit 80da7ef

File tree

3 files changed

+78
-23
lines changed

3 files changed

+78
-23
lines changed

doc/guides/rel_notes/release_24_11.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ New Features
8282

8383
The new statistics are useful for debugging and profiling.
8484

85+
* **Hardened rte_malloc and related functions.**
86+
87+
Added function attributes to ``rte_malloc`` and similar functions
88+
that can catch some obvious bugs at compile time (with GCC 11.0 or later).
89+
Examples: calling ``free`` on pointer that was allocated with ``rte_malloc``
90+
(and vice versa); freeing the same pointer twice in the same routine;
91+
freeing an object that was not created by allocation; etc.
92+
8593
* **Added cryptodev queue pair reset support.**
8694

8795
A new API ``rte_cryptodev_queue_pair_reset`` is added

lib/eal/include/rte_common.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,40 @@ typedef uint16_t unaligned_uint16_t;
228228
#define __rte_alloc_size(...)
229229
#endif
230230

231+
/**
232+
* Tells the compiler that the function returns a value that points to
233+
* memory aligned by a function argument.
234+
*
235+
* Note: not enabled on Clang because it warns if align argument is zero.
236+
*/
237+
#if defined(RTE_CC_GCC)
238+
#define __rte_alloc_align(argno) \
239+
__attribute__((alloc_align(argno)))
240+
#else
241+
#define __rte_alloc_align(argno)
242+
#endif
243+
244+
/**
245+
* Tells the compiler this is a function like malloc and that the pointer
246+
* returned cannot alias any other pointer (ie new memory).
247+
*/
248+
#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
249+
#define __rte_malloc __attribute__((__malloc__))
250+
#else
251+
#define __rte_malloc
252+
#endif
253+
254+
/**
255+
* With recent GCC versions also able to track that proper
256+
* deallocator function is used for this pointer.
257+
*/
258+
#if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 110000)
259+
#define __rte_dealloc(dealloc, argno) \
260+
__attribute__((malloc(dealloc, argno)))
261+
#else
262+
#define __rte_dealloc(dealloc, argno)
263+
#endif
264+
231265
#define RTE_PRIORITY_LOG 101
232266
#define RTE_PRIORITY_BUS 110
233267
#define RTE_PRIORITY_CLASS 120

lib/eal/include/rte_malloc.h

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ struct rte_malloc_socket_stats {
3131
size_t heap_allocsz_bytes; /**< Total allocated bytes on heap */
3232
};
3333

34+
/**
35+
* Functions that expect return value to be freed with rte_free()
36+
*/
37+
#define __rte_dealloc_free __rte_dealloc(rte_free, 1)
38+
39+
/**
40+
* Frees the memory space pointed to by the provided pointer.
41+
*
42+
* This pointer must have been returned by a previous call to
43+
* rte_malloc(), rte_zmalloc(), rte_calloc() or rte_realloc(). The behaviour of
44+
* rte_free() is undefined if the pointer does not match this requirement.
45+
*
46+
* If the pointer is NULL, the function does nothing.
47+
*
48+
* @param ptr
49+
* The pointer to memory to be freed.
50+
*/
51+
void
52+
rte_free(void *ptr);
53+
3454
/**
3555
* This function allocates memory from the huge-page area of memory. The memory
3656
* is not cleared. In NUMA systems, the memory allocated resides on the same
@@ -54,7 +74,8 @@ struct rte_malloc_socket_stats {
5474
*/
5575
void *
5676
rte_malloc(const char *type, size_t size, unsigned align)
57-
__rte_alloc_size(2);
77+
__rte_alloc_size(2) __rte_alloc_align(3)
78+
__rte_malloc __rte_dealloc_free;
5879

5980
/**
6081
* Allocate zeroed memory from the heap.
@@ -81,7 +102,8 @@ rte_malloc(const char *type, size_t size, unsigned align)
81102
*/
82103
void *
83104
rte_zmalloc(const char *type, size_t size, unsigned align)
84-
__rte_alloc_size(2);
105+
__rte_alloc_size(2) __rte_alloc_align(3)
106+
__rte_malloc __rte_dealloc_free;
85107

86108
/**
87109
* Replacement function for calloc(), using huge-page memory. Memory area is
@@ -108,7 +130,8 @@ rte_zmalloc(const char *type, size_t size, unsigned align)
108130
*/
109131
void *
110132
rte_calloc(const char *type, size_t num, size_t size, unsigned align)
111-
__rte_alloc_size(2, 3);
133+
__rte_alloc_size(2, 3) __rte_alloc_align(4)
134+
__rte_malloc __rte_dealloc_free;
112135

113136
/**
114137
* Replacement function for realloc(), using huge-page memory. Reserved area
@@ -132,7 +155,8 @@ rte_calloc(const char *type, size_t num, size_t size, unsigned align)
132155
*/
133156
void *
134157
rte_realloc(void *ptr, size_t size, unsigned int align)
135-
__rte_alloc_size(2);
158+
__rte_alloc_size(2) __rte_alloc_align(3)
159+
__rte_malloc __rte_dealloc_free;
136160

137161
/**
138162
* Replacement function for realloc(), using huge-page memory. Reserved area
@@ -158,7 +182,8 @@ rte_realloc(void *ptr, size_t size, unsigned int align)
158182
*/
159183
void *
160184
rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)
161-
__rte_alloc_size(2);
185+
__rte_alloc_size(2) __rte_alloc_align(3)
186+
__rte_malloc __rte_dealloc_free;
162187

163188
/**
164189
* This function allocates memory from the huge-page area of memory. The memory
@@ -185,7 +210,8 @@ rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)
185210
*/
186211
void *
187212
rte_malloc_socket(const char *type, size_t size, unsigned align, int socket)
188-
__rte_alloc_size(2);
213+
__rte_alloc_size(2) __rte_alloc_align(3)
214+
__rte_malloc __rte_dealloc_free;
189215

190216
/**
191217
* Allocate zeroed memory from the heap.
@@ -214,7 +240,8 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket)
214240
*/
215241
void *
216242
rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket)
217-
__rte_alloc_size(2);
243+
__rte_alloc_size(2) __rte_alloc_align(3)
244+
__rte_malloc __rte_dealloc_free;
218245

219246
/**
220247
* Replacement function for calloc(), using huge-page memory. Memory area is
@@ -243,22 +270,8 @@ rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket)
243270
*/
244271
void *
245272
rte_calloc_socket(const char *type, size_t num, size_t size, unsigned align, int socket)
246-
__rte_alloc_size(2, 3);
247-
248-
/**
249-
* Frees the memory space pointed to by the provided pointer.
250-
*
251-
* This pointer must have been returned by a previous call to
252-
* rte_malloc(), rte_zmalloc(), rte_calloc() or rte_realloc(). The behaviour of
253-
* rte_free() is undefined if the pointer does not match this requirement.
254-
*
255-
* If the pointer is NULL, the function does nothing.
256-
*
257-
* @param ptr
258-
* The pointer to memory to be freed.
259-
*/
260-
void
261-
rte_free(void *ptr);
273+
__rte_alloc_size(2, 3) __rte_alloc_align(4)
274+
__rte_malloc __rte_dealloc_free;
262275

263276
/**
264277
* If malloc debug is enabled, check a memory block for header

0 commit comments

Comments
 (0)