Files
libakerror/tests/err_unhandled_null.c

62 lines
2.0 KiB
C
Raw Normal View History

#include "akerror.h"
#include "err_capture.h"
#include <unistd.h>
#include <sys/wait.h>
/*
* The default unhandled-error handler is the library's last stop: it exits the
* process. Both of its exits were untested -- exit(1) for a NULL context (a
* handler invoked with no error at all) and exit(errctx->status) for a real one.
*
* The handler never returns, so each case runs in a forked child and the test
* asserts the exact exit status. That is stricter than a WILL_FAIL test, which
* would pass on any non-zero exit, including one caused by an unrelated bug.
*/
/*
* Run the default handler on ctx in a child process and return the child's exit
* status, or -1 if it did not exit normally. The _exit() sentinel catches a
* handler that returns instead of terminating.
*/
static int handler_exit_status(akerr_ErrorContext *ctx)
{
pid_t pid = fork();
if ( pid == 0 ) {
akerr_default_handler_unhandled_error(ctx);
_exit(99);
}
int status = 0;
if ( pid < 0 || waitpid(pid, &status, 0) != pid || !WIFEXITED(status) ) {
return -1;
}
return WEXITSTATUS(status);
}
int main(void)
{
akerr_capture_install();
akerr_init();
/* No context to report: the handler has nothing to exit with but failure. */
AKERR_CHECK(handler_exit_status(NULL) == 1);
/*
* With a context, the status becomes the exit code. waitpid only reports
* its low 8 bits, which is where AKERR_VALUE (144) lands, and it is neither
* 0 nor the 1 used for the NULL case, so the two exits stay distinguishable.
*/
akerr_ErrorContext *slot = akerr_next_error();
AKERR_CHECK(slot != NULL);
slot->refcount = 1;
slot->status = AKERR_VALUE;
AKERR_CHECK((AKERR_VALUE & 0xff) != 0 && (AKERR_VALUE & 0xff) != 1);
AKERR_CHECK(handler_exit_status(slot) == (AKERR_VALUE & 0xff));
slot = akerr_release_error(slot);
AKERR_CHECK(slot == NULL);
AKERR_CHECK(akerr_slots_in_use() == 0);
fprintf(stderr, "err_unhandled_null ok\n");
return 0;
}