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