1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file test dynamic memory allocation using C libraries
9 *
10 * This module verifies that the various dynamic memory allocation functions
11 * works fine with minimal C library and newlib C library.
12 *
13 * IMPORTANT: The module only ensures that each supported library is present,
14 * and that a bare minimum of its functionality is operating correctly. It does
15 * NOT guarantee that ALL standards-defined functionality is present, nor does
16 * it guarantee that ALL functionality provided is working correctly.
17 */
18
19 #if defined(__GNUC__)
20 /*
21 * Don't complain about ridiculous alloc size requests
22 */
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Walloc-size-larger-than="
25 #endif
26
27 #define _BSD_SOURCE
28 #include <zephyr/kernel.h>
29 #include <zephyr/ztest.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <time.h>
33 #include <stdint.h>
34
35 #define TOO_BIG PTRDIFF_MAX
36
37 /**
38 *
39 * @brief Test implementation-defined constants library
40 * @defgroup libc_api
41 * @ingroup all_tests
42 * @{
43 *
44 */
45
46 #define BUF_LEN 10
47
48
49 /* The access test allocates objects of this type and dereferences members. */
50 union aligntest {
51 long long thelonglong;
52 double thedouble;
53 uintmax_t theuintmax_t;
54 void (*thepfunc)(void);
55 time_t thetime_t;
56 };
57
58
59 #if defined(CONFIG_COMMON_LIBC_MALLOC) && \
60 (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE == 0)
_test_no_mem_malloc(void)61 __no_optimization void _test_no_mem_malloc(void)
62 {
63 int *iptr = NULL;
64
65 iptr = malloc(BUF_LEN);
66 zassert_is_null((iptr), "malloc failed, errno: %d", errno);
67 free(iptr);
68 iptr = NULL;
69 }
70
ZTEST(c_lib_dynamic_memalloc,test_no_mem_malloc)71 ZTEST(c_lib_dynamic_memalloc, test_no_mem_malloc)
72 {
73 _test_no_mem_malloc();
74 }
75
_test_no_mem_realloc(void)76 __no_optimization void _test_no_mem_realloc(void)
77 {
78 char *ptr = NULL;
79 char *reloc_ptr = NULL;
80
81 reloc_ptr = realloc(ptr, BUF_LEN);
82 zassert_is_null(reloc_ptr, "realloc failed, errno: %d", errno);
83 free(reloc_ptr);
84 reloc_ptr = NULL;
85 }
86
ZTEST(c_lib_dynamic_memalloc,test_no_mem_realloc)87 ZTEST(c_lib_dynamic_memalloc, test_no_mem_realloc)
88 {
89 _test_no_mem_realloc();
90 }
91 #else
92 /* Make sure we can access some built-in types. */
do_the_access(volatile union aligntest * aptr)93 static void do_the_access(volatile union aligntest *aptr)
94 {
95 aptr->thelonglong = 2;
96 aptr->thelonglong;
97
98 if (IS_ENABLED(CONFIG_FPU)) {
99 aptr->thedouble = 3.0;
100 aptr->thedouble;
101 }
102
103 aptr->theuintmax_t = 4;
104 aptr->theuintmax_t;
105
106 aptr->thepfunc = test_main;
107 aptr->thepfunc;
108
109 aptr->thetime_t = 3;
110 aptr->thetime_t;
111 }
112
113 #define PRINT_TYPE_INFO(_t) \
114 TC_PRINT(" %-14s %4zu %5zu\n", #_t, sizeof(_t), __alignof__(_t))
115
ZTEST(c_lib_dynamic_memalloc,test_malloc_align)116 ZTEST(c_lib_dynamic_memalloc, test_malloc_align)
117 {
118 char *ptr[64] = { NULL };
119
120 TC_PRINT(" Compiler type info for " CONFIG_ARCH " " CONFIG_BOARD "\n");
121 TC_PRINT(" TYPE SIZE ALIGN\n");
122 PRINT_TYPE_INFO(int);
123 PRINT_TYPE_INFO(long);
124 PRINT_TYPE_INFO(long long);
125 PRINT_TYPE_INFO(double);
126 PRINT_TYPE_INFO(size_t);
127 PRINT_TYPE_INFO(void *);
128 PRINT_TYPE_INFO(void (*)(void));
129 PRINT_TYPE_INFO(time_t);
130
131 /* Tries to use the malloc() implementation when in different states. */
132 for (size_t i = 0; i < ARRAY_SIZE(ptr); i++) {
133 union aligntest *aptr = NULL;
134
135 ptr[i] = malloc(sizeof *(ptr[i]));
136 aptr = malloc(sizeof(*aptr));
137 if (aptr) {
138 do_the_access(aptr);
139 }
140 free(aptr);
141 }
142 for (size_t i = 0; i < ARRAY_SIZE(ptr); i++) {
143 free(ptr[i]);
144 ptr[i] = NULL;
145 }
146
147 for (size_t n = 0; n < ARRAY_SIZE(ptr); n++) {
148 union aligntest *aptr = NULL;
149
150 for (size_t i = 0; i < n; i++) {
151 ptr[i] = malloc(sizeof *(ptr[i]));
152 }
153 aptr = malloc(sizeof(*aptr));
154 if (aptr) {
155 do_the_access(aptr);
156 }
157 free(aptr);
158 for (size_t i = 0; i < n; i++) {
159 free(ptr[i]);
160 ptr[i] = NULL;
161 }
162 }
163
164 for (size_t n = 0; n < ARRAY_SIZE(ptr); n++) {
165 union aligntest *aptr = NULL;
166
167 ptr[n] = malloc(n);
168 aptr = malloc(sizeof(*aptr));
169 if (aptr) {
170 do_the_access(aptr);
171 }
172 free(aptr);
173 free(ptr[n]);
174 ptr[n] = NULL;
175 }
176 }
177
178 /**
179 * @brief Test dynamic memory allocation using malloc
180 *
181 * @see malloc(), free()
182 */
ZTEST(c_lib_dynamic_memalloc,test_malloc)183 ZTEST(c_lib_dynamic_memalloc, test_malloc)
184 {
185 /* Initialize error number to avoid garbage value, in case of SUCCESS */
186 int *iptr = NULL;
187
188 iptr = malloc(BUF_LEN * sizeof(int));
189 zassert_not_null((iptr), "malloc failed, errno: %d", errno);
190 memset(iptr, 'p', BUF_LEN * sizeof(int));
191 free(iptr);
192 iptr = NULL;
193 }
194
195 /**
196 * @brief Test dynamic memory allocation free function
197 *
198 * @see free()
199 */
ZTEST(c_lib_dynamic_memalloc,test_free)200 ZTEST(c_lib_dynamic_memalloc, test_free)
201 {
202 /*
203 * In free, if ptr is passed as NULL, no operation is performed
204 * Just make sure, no exception occurs and test pass
205 */
206 free(NULL);
207 }
208
209 /**
210 * @brief Test dynamic memory allocation using realloc
211 *
212 * @see malloc(), realloc(), free()
213 */
214 ZTEST_BMEM unsigned char filled_buf[BUF_LEN];
215
ZTEST(c_lib_dynamic_memalloc,test_realloc)216 ZTEST(c_lib_dynamic_memalloc, test_realloc)
217 {
218 char orig_size = BUF_LEN;
219 char new_size = BUF_LEN + BUF_LEN;
220 char *ptr = NULL;
221 char *reloc_ptr = NULL;
222
223 ptr = malloc(orig_size);
224
225 zassert_not_null((ptr), "malloc failed, errno: %d", errno);
226 (void)memset(ptr, 'p', orig_size);
227
228 reloc_ptr = realloc(ptr, new_size);
229
230 zassert_not_null(reloc_ptr, "realloc failed, errno: %d", errno);
231 ptr = reloc_ptr;
232
233 (void)memset(filled_buf, 'p', BUF_LEN);
234 zassert_true(((memcmp(ptr, filled_buf, BUF_LEN)) == 0),
235 "realloc failed to copy malloc data, errno: %d", errno);
236
237 free(ptr);
238 ptr = NULL;
239 }
240
241 /**
242 * @brief Test dynamic memory allocation using reallocarray
243 *
244 * @see malloc(), reallocarray(), free()
245 */
246 #if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARMCLANG_STD_LIBC)
ZTEST(c_lib_dynamic_memalloc,test_reallocarray)247 ZTEST(c_lib_dynamic_memalloc, test_reallocarray)
248 {
249 /* reallocarray not implemented for newlib or arm libc */
250 ztest_test_skip();
251 }
ZTEST(c_lib_dynamic_memalloc,test_calloc)252 ZTEST(c_lib_dynamic_memalloc, test_calloc)
253 {
254 ztest_test_skip();
255 }
256 #else
257 /**
258 * @brief Test dynamic memory allocation using calloc
259 *
260 * @see calloc(), free()
261 */
262 #define CALLOC_BUFLEN (200)
263 static ZTEST_BMEM unsigned char zerobuf[CALLOC_BUFLEN];
264
_test_calloc(void)265 __no_optimization void _test_calloc(void)
266 {
267 char *cptr = NULL;
268
269 cptr = calloc(TOO_BIG, sizeof(int));
270 zassert_is_null((cptr), "calloc failed, errno: %d", errno);
271 free(cptr);
272
273 cptr = calloc(TOO_BIG, sizeof(char));
274 zassert_is_null((cptr), "calloc failed, errno: %d", errno);
275 free(cptr);
276
277 cptr = calloc(CALLOC_BUFLEN, sizeof(char));
278 zassert_not_null((cptr), "calloc failed, errno: %d", errno);
279 zassert_true(((memcmp(cptr, zerobuf, CALLOC_BUFLEN)) == 0),
280 "calloc failed to set zero value, errno: %d", errno);
281 memset(cptr, 'p', CALLOC_BUFLEN);
282 free(cptr);
283 cptr = NULL;
284 }
ZTEST(c_lib_dynamic_memalloc,test_calloc)285 ZTEST(c_lib_dynamic_memalloc, test_calloc)
286 {
287 _test_calloc();
288 }
289
ZTEST(c_lib_dynamic_memalloc,test_reallocarray)290 ZTEST(c_lib_dynamic_memalloc, test_reallocarray)
291 {
292 char orig_size = BUF_LEN;
293 char *ptr = NULL;
294 char *cptr = NULL;
295
296 cptr = reallocarray(ptr, TOO_BIG, sizeof(int));
297 zassert_is_null((ptr), "reallocarray failed, errno: %d", errno);
298 zassert_is_null((cptr), "reallocarray failed, errno: %d");
299 free(cptr);
300
301 ptr = malloc(orig_size);
302
303 zassert_not_null((ptr), "malloc failed, errno: %d", errno);
304 (void)memset(ptr, 'p', orig_size);
305
306 char *reloc_ptr = reallocarray(ptr, 2, orig_size);
307
308 zassert_not_null(reloc_ptr, "reallocarray failed");
309 zassert_not_null((ptr), "malloc/reallocarray failed, errno: %d", errno);
310 ptr = reloc_ptr;
311
312 (void)memset(filled_buf, 'p', BUF_LEN);
313 zassert_true(((memcmp(ptr, filled_buf, BUF_LEN)) == 0),
314 "realloc failed to copy malloc data, errno: %d", errno);
315
316 free(ptr);
317 ptr = NULL;
318 }
319 #endif
320
321
322 #define MAX_LEN (10 * BUF_LEN)
323
324 /**
325 * @brief Test dynamic memory allocation functions
326 *
327 * @see malloc(), calloc(), realloc(), free()
328 */
ZTEST(c_lib_dynamic_memalloc,test_memalloc_all)329 ZTEST(c_lib_dynamic_memalloc, test_memalloc_all)
330 {
331 char *mlc_ptr = NULL;
332 char *clc_ptr = NULL;
333 char *reloc_ptr = NULL;
334 int orig_size = BUF_LEN;
335 int new_size = MAX_LEN;
336
337 mlc_ptr = malloc(orig_size);
338 zassert_not_null((mlc_ptr), "malloc failed, errno: %d", errno);
339
340 clc_ptr = calloc(100, sizeof(char));
341 zassert_not_null((clc_ptr), "calloc failed, errno: %d", errno);
342
343 reloc_ptr = realloc(mlc_ptr, new_size);
344 zassert_not_null(reloc_ptr, "realloc failed, errno: %d", errno);
345 mlc_ptr = reloc_ptr;
346
347 free(mlc_ptr);
348 free(clc_ptr);
349 mlc_ptr = NULL;
350 clc_ptr = NULL;
351 reloc_ptr = NULL;
352 }
353
354 /**
355 * @}
356 */
357
358 /**
359 *
360 * @brief Test dynamic memory allocation upto maximum size
361 * Negative test case
362 *
363 */
_test_memalloc_max(void)364 __no_optimization void _test_memalloc_max(void)
365 {
366 char *ptr = NULL;
367
368 ptr = malloc(TOO_BIG);
369 zassert_is_null(ptr, "malloc passed unexpectedly");
370 free(ptr);
371 ptr = NULL;
372 }
373
ZTEST(c_lib_dynamic_memalloc,test_memalloc_max)374 ZTEST(c_lib_dynamic_memalloc, test_memalloc_max)
375 {
376 _test_memalloc_max();
377 }
378 #endif
379
380 ZTEST_SUITE(c_lib_dynamic_memalloc, NULL, NULL, NULL, NULL, NULL);
381