Re: [PATCH 2/3] selftests/nolibc: test the memory allocator

From: Willy Tarreau

Date: Sat Apr 04 2026 - 04:54:35 EST


On Wed, Apr 01, 2026 at 05:07:28PM +0200, Thomas Weißschuh wrote:
> The memory allocator has not seen any testing so far.

Oh indeed, I thought we already had such a test!

> Add a simple testcase for it.
>
> Signed-off-by: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
> ---
> tools/testing/selftests/nolibc/nolibc-test.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
> index 1efd10152e83..c888e13c6bd8 100644
> --- a/tools/testing/selftests/nolibc/nolibc-test.c
> +++ b/tools/testing/selftests/nolibc/nolibc-test.c
> @@ -1554,6 +1554,30 @@ int test_time_types(void)
> return 0;
> }
>
> +int test_malloc(void)
> +{
> + void *ptr1, *ptr2, *ptr3;
> +
> + ptr1 = malloc(100);
> + if (!ptr1)
> + return 1;
> +
> + ptr2 = realloc(ptr1, 200);
> + if (!ptr2) {
> + free(ptr1);
> + return 2;
> + }
> +
> + ptr3 = realloc(ptr2, 2 * getpagesize());
> + if (!ptr3) {
> + free(ptr2);
> + return 3;
> + }
> +
> + free(ptr3);
> + return 0;
> +}
> +

I think we could enhance the test, because there are two key points
that it doesn't cover:
- realloc must preserve contents
- we need to make sure that more than one area exists (e.g. a naive
implementation always returning the same pointer to a buffer would
succeed).

What about something like this which would test malloc/calloc/realloc
and free (untested, sorry if I got some indexes wrong, but you get the
idea) ?

int test_malloc(void)
{
int *array1, *array2, *array3;
int idx;

/* 1000 to allocate less than a page */
array1 = malloc(1000 * sizeof(*array1));
if (!array1)
return 1;
for (idx = 0; idx < 1000; idx++)
array1[idx] = idx;

/* 2000 to allocate more than a page */
array2 = calloc(2000, sizeof(*array2));
if (!array2) {
free(array1);
return 2;
}
for (idx = 0; idx < 2000; idx++)
array1[idx] = idx + 1000;

/* resize array1 into array3 and append array2 at the end,
* this requires 3 pages. On success, array1 is freed.
*/
array3 = realloc(array1, 3000 * sizeof(*array3));
if (!array3) {
free(array2);
free(array1);
return 3;
}
memcpy(array3 + 1000, array2, sizeof(*array2) * 2000);
free(array2);

/* the contents must be contiguous now */
for (idx = 0; idx < 3000; idx++)
if (array3[idx] != idx)
return 4;
free(array3);
return 0;
}

> int run_stdlib(int min, int max)
> {
> int test;
> @@ -1680,6 +1704,7 @@ int run_stdlib(int min, int max)
> CASE_TEST(memchr_foobar6_o); EXPECT_STREQ(1, memchr("foobar", 'o', 6), "oobar"); break;
> CASE_TEST(memchr_foobar3_b); EXPECT_STRZR(1, memchr("foobar", 'b', 3)); break;
> CASE_TEST(time_types); EXPECT_ZR(is_nolibc, test_time_types()); break;
> + CASE_TEST(malloc); EXPECT_ZR(1, test_malloc()); break;
>
> case __LINE__:
> return ret; /* must be last */

So it's as you prefer, in any case, I'm obviously OK with the extra test.

Acked-by: Willy Tarreau <w@xxxxxx>

Willy