pointers-memory · intermediate · ~25 min

Grow a buffer and zero only the new region

Realloc + explicit zero-fill, with attention to OOM.

Challenge

Resize a heap buffer with realloc, then zero only the newly added bytes. realloc leaves the extended region uninitialised — it may contain stale heap data — so zeroing just the new part is the safe building block.

Task

Implement void *grow_zeroed(void *ptr, size_t old_size, size_t new_size) that calls realloc(ptr, new_size), zeroes the bytes from old_size up to new_size when growing, and returns the new pointer. No main — the grader calls it.

Input

ptr — the existing block (may be NULL, in which case this acts like malloc). old_size — its current size in bytes. new_size — the desired size in bytes.

Output

Returns the resized pointer, with bytes [old_size, new_size) set to 0 when growing. Returns NULL on allocation failure — in that case the original ptr is still valid and must NOT be freed.

Example

char *p = malloc(4); memcpy(p, "abc", 4);
p = grow_zeroed(p, 4, 16)    ->   "abc\0" preserved, bytes 4..15 all zero

char *p = malloc(16); memset(p, 'X', 16);
p = grow_zeroed(p, 16, 8)    ->   shrunk; no zero-fill needed

Edge cases

  • ptr == NULL: behaves like malloc(new_size) then zeroes it.
  • Shrinking (new_size <= old_size): no zero-fill.
  • Allocation failure: return NULL, leave the original block alive.

Rules

  • realloc into a temporary so an OOM doesn't lose (and leak) the original.
  • Zero only the new region, not the whole buffer.

Why this matters

realloc enlarges a buffer but leaves the new region uninitialised — that's a subtle source of information leaks (a CVE in OpenSSL leaked private-key bytes this way). Wrapping realloc with explicit zeroing of just the new region is the safer building block.

Input format

ptr (may be NULL), current old_size, desired new_size (bytes).

Output format

The resized pointer with the new region zeroed, or NULL on failure.

Constraints

Use realloc (into a temporary) + memset. Zero only the new region. Don't free on OOM.

Starter code

#include <stddef.h>
void *grow_zeroed(void *ptr, size_t old_size, size_t new_size) { /* TODO */ return NULL; }

Common mistakes

Doing ptr = realloc(ptr, new_size) — if realloc returns NULL, the original is lost (leak). Use a temporary. Zeroing the whole buffer (defeats the purpose of realloc when shrinking).

Edge cases to handle

new_size == 0 (call free or realloc-to-0, depending on impl); shrink (no zero-fill); grow (zero only the new region); ptr == NULL (acts like malloc).

Complexity

Amortised O(new_size - old_size) for the zero-fill plus realloc cost.

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.