#include "akerror.h" #include "err_capture.h" #include /* * Regression test for the stack-trace buffer overflow. Each frame appended a * line with snprintf, but passed the *full* buffer length as the size rather * than the space remaining, and advanced the cursor by snprintf's would-be * return value. A trace that filled the buffer therefore wrote past the end of * stacktracebuf and ran the cursor out of bounds. * * We place a context in a struct with a guard region right after it, position * the trace cursor near the end of the buffer, append one more frame, and * require that nothing was written past the buffer and the cursor stayed in * bounds. */ static struct { akerr_ErrorContext ctx; unsigned char guard[512]; } probe; akerr_ErrorContext *append_frame(akerr_ErrorContext *e) { FAIL_RETURN(e, AKERR_VALUE, "an error message long enough to overflow a nearly full stack trace buffer"); } int main(void) { akerr_init(); memset(&probe, 0x00, sizeof(probe)); memset(probe.guard, 0xAA, sizeof(probe.guard)); akerr_ErrorContext *e = &probe.ctx; e->refcount = 1; /* Two bytes short of full: any real frame would overflow the old code. */ e->stacktracebufptr = probe.ctx.stacktracebuf + AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH - 2; (void)append_frame(e); /* Nothing may have been written past the end of stacktracebuf. */ for ( unsigned i = 0; i < sizeof(probe.guard); i++ ) { AKERR_CHECK(probe.guard[i] == 0xAA); } /* The cursor must remain within the buffer. */ AKERR_CHECK(e->stacktracebufptr <= probe.ctx.stacktracebuf + AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH); fprintf(stderr, "err_stacktrace_bounds ok\n"); return 0; }