cybersecurity · intermediate · ~20 min
Defensive concat with truncation reporting; the strlcat contract.
Implement size_t safe_strncat(char *dst, size_t cap, const char *src):
dst is a NUL-terminated string in a buffer of total size cap.src as fits — leaving room for the NUL terminator at the end.dst (even if dst was malformed, do your best).cap were infinite (the way snprintf and strlcat do — useful for detecting truncation).If dst doesn't already end in NUL within cap bytes, return cap and leave dst unchanged (mirrors strlcat's defensive behaviour).
char buf[16] = "hi";
safe_strncat(buf, 16, "!") -> 3, buf == "hi!"
char buf[6] = "hi";
safe_strncat(buf, 6, "!world") -> 8, buf == "hi!wo" // truncated, return == would-be length
char buf[16] = "";
safe_strncat(buf, 16, "abc") -> 3, buf == "abc"
char buf[16] = "hello";
safe_strncat(buf, 16, "") -> 5, buf == "hello"
strncat has a famously hostile API (the third argument is the max bytes appended, NOT the buffer size). Writing a saner version forces you to internalise the off-by-one nightmare that has produced so many CVEs.
dst NUL-terminated within cap bytes; src NUL-terminated.
See API.
No undefined behaviour even if dst doesn't fit a NUL in cap.
#include <stddef.h>
size_t safe_strncat(char *dst, size_t cap, const char *src) { /* TODO */ return 0; }
Confusing cap (buffer size) with 'max bytes to append' (the strncat trap). Forgetting the +1 for the NUL.
Empty src; empty dst; src bigger than remaining space; dst missing its NUL.
O(strlen(dst) + strlen(src)).
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.