/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /* * @file test dynamic memory allocation using C libraries * * This module verifies that the various dynamic memory allocation functions * works fine with minimal C library and newlib C library. * * IMPORTANT: The module only ensures that each supported library is present, * and that a bare minimum of its functionality is operating correctly. It does * NOT guarantee that ALL standards-defined functionality is present, nor does * it guarantee that ALL functionality provided is working correctly. */ #if defined(__GNUC__) /* * Don't complain about ridiculous alloc size requests */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Walloc-size-larger-than=" #endif #define _BSD_SOURCE #include #include #include #include #include #include #define TOO_BIG PTRDIFF_MAX /** * * @brief Test implementation-defined constants library * @defgroup libc_api * @ingroup all_tests * @{ * */ #define BUF_LEN 10 /* The access test allocates objects of this type and dereferences members. */ union aligntest { long long thelonglong; double thedouble; uintmax_t theuintmax_t; void (*thepfunc)(void); time_t thetime_t; }; #if defined(CONFIG_COMMON_LIBC_MALLOC) && \ (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE == 0) __no_optimization void _test_no_mem_malloc(void) { int *iptr = NULL; iptr = malloc(BUF_LEN); zassert_is_null((iptr), "malloc failed, errno: %d", errno); free(iptr); iptr = NULL; } ZTEST(c_lib_dynamic_memalloc, test_no_mem_malloc) { _test_no_mem_malloc(); } __no_optimization void _test_no_mem_realloc(void) { char *ptr = NULL; char *reloc_ptr = NULL; reloc_ptr = realloc(ptr, BUF_LEN); zassert_is_null(reloc_ptr, "realloc failed, errno: %d", errno); free(reloc_ptr); reloc_ptr = NULL; } ZTEST(c_lib_dynamic_memalloc, test_no_mem_realloc) { _test_no_mem_realloc(); } #else /* Make sure we can access some built-in types. */ static void do_the_access(volatile union aligntest *aptr) { aptr->thelonglong = 2; aptr->thelonglong; if (IS_ENABLED(CONFIG_FPU)) { aptr->thedouble = 3.0; aptr->thedouble; } aptr->theuintmax_t = 4; aptr->theuintmax_t; aptr->thepfunc = test_main; aptr->thepfunc; aptr->thetime_t = 3; aptr->thetime_t; } #define PRINT_TYPE_INFO(_t) \ TC_PRINT(" %-14s %4zu %5zu\n", #_t, sizeof(_t), __alignof__(_t)) ZTEST(c_lib_dynamic_memalloc, test_malloc_align) { char *ptr[64] = { NULL }; TC_PRINT(" Compiler type info for " CONFIG_ARCH " " CONFIG_BOARD "\n"); TC_PRINT(" TYPE SIZE ALIGN\n"); PRINT_TYPE_INFO(int); PRINT_TYPE_INFO(long); PRINT_TYPE_INFO(long long); PRINT_TYPE_INFO(double); PRINT_TYPE_INFO(size_t); PRINT_TYPE_INFO(void *); PRINT_TYPE_INFO(void (*)(void)); PRINT_TYPE_INFO(time_t); /* Tries to use the malloc() implementation when in different states. */ for (size_t i = 0; i < ARRAY_SIZE(ptr); i++) { union aligntest *aptr = NULL; ptr[i] = malloc(sizeof *(ptr[i])); aptr = malloc(sizeof(*aptr)); if (aptr) { do_the_access(aptr); } free(aptr); } for (size_t i = 0; i < ARRAY_SIZE(ptr); i++) { free(ptr[i]); ptr[i] = NULL; } for (size_t n = 0; n < ARRAY_SIZE(ptr); n++) { union aligntest *aptr = NULL; for (size_t i = 0; i < n; i++) { ptr[i] = malloc(sizeof *(ptr[i])); } aptr = malloc(sizeof(*aptr)); if (aptr) { do_the_access(aptr); } free(aptr); for (size_t i = 0; i < n; i++) { free(ptr[i]); ptr[i] = NULL; } } for (size_t n = 0; n < ARRAY_SIZE(ptr); n++) { union aligntest *aptr = NULL; ptr[n] = malloc(n); aptr = malloc(sizeof(*aptr)); if (aptr) { do_the_access(aptr); } free(aptr); free(ptr[n]); ptr[n] = NULL; } } /** * @brief Test dynamic memory allocation using malloc * * @see malloc(), free() */ ZTEST(c_lib_dynamic_memalloc, test_malloc) { /* Initialize error number to avoid garbage value, in case of SUCCESS */ int *iptr = NULL; iptr = malloc(BUF_LEN * sizeof(int)); zassert_not_null((iptr), "malloc failed, errno: %d", errno); memset(iptr, 'p', BUF_LEN * sizeof(int)); free(iptr); iptr = NULL; } /** * @brief Test dynamic memory allocation free function * * @see free() */ ZTEST(c_lib_dynamic_memalloc, test_free) { /* * In free, if ptr is passed as NULL, no operation is performed * Just make sure, no exception occurs and test pass */ free(NULL); } /** * @brief Test dynamic memory allocation using realloc * * @see malloc(), realloc(), free() */ ZTEST_BMEM unsigned char filled_buf[BUF_LEN]; ZTEST(c_lib_dynamic_memalloc, test_realloc) { char orig_size = BUF_LEN; char new_size = BUF_LEN + BUF_LEN; char *ptr = NULL; char *reloc_ptr = NULL; ptr = malloc(orig_size); zassert_not_null((ptr), "malloc failed, errno: %d", errno); (void)memset(ptr, 'p', orig_size); reloc_ptr = realloc(ptr, new_size); zassert_not_null(reloc_ptr, "realloc failed, errno: %d", errno); ptr = reloc_ptr; (void)memset(filled_buf, 'p', BUF_LEN); zassert_true(((memcmp(ptr, filled_buf, BUF_LEN)) == 0), "realloc failed to copy malloc data, errno: %d", errno); free(ptr); ptr = NULL; } /** * @brief Test dynamic memory allocation using reallocarray * * @see malloc(), reallocarray(), free() */ #if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) ZTEST(c_lib_dynamic_memalloc, test_reallocarray) { /* reallocarray not implemented for newlib or arm libc */ ztest_test_skip(); } ZTEST(c_lib_dynamic_memalloc, test_calloc) { ztest_test_skip(); } #else /** * @brief Test dynamic memory allocation using calloc * * @see calloc(), free() */ #define CALLOC_BUFLEN (200) static ZTEST_BMEM unsigned char zerobuf[CALLOC_BUFLEN]; __no_optimization void _test_calloc(void) { char *cptr = NULL; cptr = calloc(TOO_BIG, sizeof(int)); zassert_is_null((cptr), "calloc failed, errno: %d", errno); free(cptr); cptr = calloc(TOO_BIG, sizeof(char)); zassert_is_null((cptr), "calloc failed, errno: %d", errno); free(cptr); cptr = calloc(CALLOC_BUFLEN, sizeof(char)); zassert_not_null((cptr), "calloc failed, errno: %d", errno); zassert_true(((memcmp(cptr, zerobuf, CALLOC_BUFLEN)) == 0), "calloc failed to set zero value, errno: %d", errno); memset(cptr, 'p', CALLOC_BUFLEN); free(cptr); cptr = NULL; } ZTEST(c_lib_dynamic_memalloc, test_calloc) { _test_calloc(); } ZTEST(c_lib_dynamic_memalloc, test_reallocarray) { char orig_size = BUF_LEN; char *ptr = NULL; char *cptr = NULL; cptr = reallocarray(ptr, TOO_BIG, sizeof(int)); zassert_is_null((ptr), "reallocarray failed, errno: %d", errno); zassert_is_null((cptr), "reallocarray failed, errno: %d"); free(cptr); ptr = malloc(orig_size); zassert_not_null((ptr), "malloc failed, errno: %d", errno); (void)memset(ptr, 'p', orig_size); char *reloc_ptr = reallocarray(ptr, 2, orig_size); zassert_not_null(reloc_ptr, "reallocarray failed"); zassert_not_null((ptr), "malloc/reallocarray failed, errno: %d", errno); ptr = reloc_ptr; (void)memset(filled_buf, 'p', BUF_LEN); zassert_true(((memcmp(ptr, filled_buf, BUF_LEN)) == 0), "realloc failed to copy malloc data, errno: %d", errno); free(ptr); ptr = NULL; } #endif #define MAX_LEN (10 * BUF_LEN) /** * @brief Test dynamic memory allocation functions * * @see malloc(), calloc(), realloc(), free() */ ZTEST(c_lib_dynamic_memalloc, test_memalloc_all) { char *mlc_ptr = NULL; char *clc_ptr = NULL; char *reloc_ptr = NULL; int orig_size = BUF_LEN; int new_size = MAX_LEN; mlc_ptr = malloc(orig_size); zassert_not_null((mlc_ptr), "malloc failed, errno: %d", errno); clc_ptr = calloc(100, sizeof(char)); zassert_not_null((clc_ptr), "calloc failed, errno: %d", errno); reloc_ptr = realloc(mlc_ptr, new_size); zassert_not_null(reloc_ptr, "realloc failed, errno: %d", errno); mlc_ptr = reloc_ptr; free(mlc_ptr); free(clc_ptr); mlc_ptr = NULL; clc_ptr = NULL; reloc_ptr = NULL; } /** * @} */ /** * * @brief Test dynamic memory allocation upto maximum size * Negative test case * */ __no_optimization void _test_memalloc_max(void) { char *ptr = NULL; ptr = malloc(TOO_BIG); zassert_is_null(ptr, "malloc passed unexpectedly"); free(ptr); ptr = NULL; } ZTEST(c_lib_dynamic_memalloc, test_memalloc_max) { _test_memalloc_max(); } #endif ZTEST_SUITE(c_lib_dynamic_memalloc, NULL, NULL, NULL, NULL, NULL);