#include "akerror.h" #include "err_capture.h" #include /* * __akerr_copy_string() is the only place in the library that writes through a * caller-supplied pointer for a caller-supplied length, so it validates every * argument and raises rather than returning quietly. Both in-library callers * check their arguments before calling it, so this test is what drives those * guards -- without it they are unreachable code that no build ever exercises. */ int main(void) { char buf[8]; akerr_capture_install(); akerr_init(); /* The happy path: bounded, and always terminated. */ memset(buf, 'x', sizeof(buf)); AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, (int)sizeof(buf), "abc")); AKERR_CHECK(strcmp(buf, "abc") == 0); /* A source longer than the buffer is truncated, never overrun. */ memset(buf, 'x', sizeof(buf)); AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, (int)sizeof(buf), "abcdefghijkl")); AKERR_CHECK(strlen(buf) == sizeof(buf) - 1); AKERR_CHECK(buf[sizeof(buf) - 1] == '\0'); AKERR_CHECK(strcmp(buf, "abcdefg") == 0); /* A capacity of exactly one holds nothing but the terminator. */ memset(buf, 'x', sizeof(buf)); AKERR_CHECK_SUCCEEDS(__akerr_copy_string(buf, 1, "abc")); AKERR_CHECK(buf[0] == '\0'); AKERR_CHECK(buf[1] == 'x'); /* and wrote nothing past its capacity */ /* NULL pointers raise instead of faulting, and the message says which. */ AKERR_CHECK_RAISES(__akerr_copy_string(NULL, (int)sizeof(buf), "abc"), AKERR_NULLPOINTER); AKERR_CHECK_MESSAGE_CONTAINS("destination"); AKERR_CHECK_RAISES(__akerr_copy_string(buf, (int)sizeof(buf), NULL), AKERR_NULLPOINTER); AKERR_CHECK_MESSAGE_CONTAINS("source"); /* A capacity with no room for a terminator is a value error, not a write. */ memset(buf, 'x', sizeof(buf)); AKERR_CHECK_RAISES(__akerr_copy_string(buf, 0, "abc"), AKERR_VALUE); AKERR_CHECK_MESSAGE_CONTAINS("capacity of 0"); AKERR_CHECK_RAISES(__akerr_copy_string(buf, -1, "abc"), AKERR_VALUE); AKERR_CHECK(buf[0] == 'x'); /* nothing was written */ /* Each refusal handed its context back to the pool. */ AKERR_CHECK(akerr_slots_in_use() == 0); fprintf(stderr, "err_copy_string ok\n"); return 0; }