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