Instead of detecting that the minimal C library is in use before running the malloc failure tests, check for the common malloc being in use as that will also allow this test to run with picolibc. Signed-off-by: Keith Packard <keithp@keithp.com>
381 lines
8.3 KiB
C
381 lines
8.3 KiB
C
/*
|
|
* 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 <zephyr/kernel.h>
|
|
#include <zephyr/ztest.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <stdint.h>
|
|
|
|
#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);
|