cybersecurity · intermediate · ~15 min · safe pentest lab

Safe bounded string concatenation

Implement bounded string concatenation with atomic rollback on overflow to prevent buffer corruption.

Challenge

In C, strncat and unchecked string appends are a frequent source of off-by-one buffer overflows. A defensive string append must strictly verify that the combined length plus NUL fits within the destination buffer capacity.

Your Task

Implement:

int safe_str_cat(char *dest, size_t dest_cap, const char *src);

Append src to dest without exceeding dest_cap (which includes the NUL byte).

Rules

  1. If dest == NULL, src == NULL, or dest_cap == 0, return -1.
  2. If dest does not contain a NUL terminator within dest_cap, return -1.
  3. If strlen(dest) + strlen(src) + 1 > dest_cap, return -1 leaving dest completely unmodified (never partially append or truncate).
  4. On success, append src, ensure dest is NUL-terminated, and return 0.

Example

char buf[10] = "foo";
safe_str_cat(buf, sizeof(buf), "bar"); // returns 0, buf is "foobar"
safe_str_cat(buf, sizeof(buf), "toolong"); // returns -1, buf remains "foobar"

Input format

dest: caller-owned buffer; dest_cap: size_t buffer capacity; src: NUL-terminated string to append.

Output format

Returns 0 on clean append; -1 on overflow or invalid inputs (leaving dest unmodified).

Constraints

Freestanding logic. No dynamic allocation. Never write past dest_cap.

Starter code

#include <stddef.h>

/* Append src to dest without exceeding dest_cap (which includes the NUL byte).
   Returns 0 on success. If src does not completely fit, or if inputs are NULL,
   or if dest has no NUL terminator within dest_cap, returns -1 leaving dest intact. */
int safe_str_cat(char *dest, size_t dest_cap, const char *src) {
    (void)dest; (void)dest_cap; (void)src;
    return -1;
}

Common mistakes

Modifying dest before verifying that src fits; computing dest length with strlen without checking dest_cap first; forgetting the byte reserved for NUL.

Edge cases to handle

dest_cap == 0 returns -1; empty src appends nothing and returns 0; exact-fit buffer (strlen + 1 == dest_cap) succeeds.

Background lessons

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