C Basics: Grow an Allocation Without Losing Its Owner
Assigning realloc directly to the only owning pointer can lose the old allocation on failure. Use a temporary pointer and reject invalid sizes before allocating.
Prepare a scratch directory
Tested on Linux x86-64 with GCC 14.2.0. You need GCC, the C development headers, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library and no external package.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1Run the example
Save this as realloc-ownership-demo.c:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
static bool resize_values(int **values, size_t count) {
if (count == 0 || count > SIZE_MAX / sizeof **values) {
return false;
}
int *replacement = realloc(*values, count * sizeof **values);
if (replacement == NULL) {
return false;
}
*values = replacement;
return true;
}
int main(void) {
int *values = NULL;
if (!resize_values(&values, 2)) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
values[0] = 10;
values[1] = 20;
if (!resize_values(&values, 4)) {
free(values);
fputs("Growth failed\n", stderr);
return EXIT_FAILURE;
}
values[2] = 30;
values[3] = 40;
printf("Values: %d %d %d %d\n", values[0], values[1], values[2], values[3]);
printf("Zero count rejected: %s\n", resize_values(&values, 0) ? "no" : "yes");
printf("First value retained: %d\n", values[0]);
free(values);
values = NULL;
return EXIT_SUCCESS;
}Compile and run it. The && prevents running an old executable if compilation fails:
gcc -std=c17 -Wall -Wextra -Werror -pedantic realloc-ownership-demo.c -o realloc-ownership-demo &&
./realloc-ownership-demoObserved output:
Values: 10 20 30 40
Zero count rejected: yes
First value retained: 10Read the result
For a nonzero requested size, a failed realloc leaves the original allocation available to its owner. On success, retain only the returned pointer. The old contents survive up to the smaller allocation size; initialize newly added elements before reading them.
Apply it carefully
The helper rejects zero to avoid version-specific zero-size behavior and checks multiplication before computing bytes. It accepts NULL initially, which behaves like allocation. A successful reallocation invalidates old aliases, including pointers into the block, even if the numeric address appears unchanged. The example exercises growth and a validation rejection, not an injected out-of-memory failure.
The library reference describes the relevant behavior.
Clean up
Remove only the source and executable created here, then remove the empty scratch directory:
rm -- realloc-ownership-demo.c realloc-ownership-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directoryIf the directory is not empty, inspect what remains before removing anything else.
Acknowledgements
This post was created with assistance from AI.