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