在Unix系统上,我可以使用fork()产生一个进程,并检查该线程的标志以判断该线程是否中止(通常是通过断言失败)。这是给定一个函数的示例代码,检查该函数调用是否中止。
bool test_assert_fail(void (*run)(void *aux), void *aux) {
if (fork()) { // parent process
int *status = malloc(sizeof(*status));
assert(status != NULL);
wait(status);
// Check whether child process aborted
bool aborted = WIFSIGNALED(*status) && WTERMSIG(*status) == SIGABRT;
free(status);
return aborted;
}
else { // child process
freopen("/dev/null", "w", stderr); // suppress assertion message
run(aux);
exit(0); // should not be reached
}
}
使用MinGW gcc编译器在Windows上执行类似操作的最简单方法是什么?线程不起作用,因为子线程中止会导致父线程也中止。我不知道该如何使用进程,因为它是一个函数调用。
NB:与此一起调用的函数非常简单并且是单线程的,因此它比通常要安全[[有点]]。我最终使用signal
捕获SIGABRT,并使用longjmp
继续执行:
#ifdef _WIN32
bool SIGABRT_RAISED = false;
jmp_buf env;
void signal_handler(int signum) {
if (signum == SIGABRT) {
SIGABRT_RAISED = true;
// Reregister default, and jump out to avoid return
signal(signum, SIG_DFL);
longjmp(env, 1);
}
}
#endif
bool test_assert_fail(void (*run)(void *aux), void *aux) {
// Windows can't use POSIX apis
#ifndef _WIN32
if (fork()) { // parent process
int *status = malloc(sizeof(*status));
assert(status != NULL);
wait(status);
// Check whether child process aborted
bool aborted = WIFSIGNALED(*status) && WTERMSIG(*status) == SIGABRT;
free(status);
return aborted;
}
else { // child process
freopen("/dev/null", "w", stderr); // suppress assertion message
run(aux);
exit(0); // should not be reached
}
#else
signal(SIGABRT, signal_handler);
SIGABRT_RAISED = false;
int cstderr = _dup(_fileno(stderr));
// Run expected failure, jumping back when SIGABRT is raised
if (setjmp(env) == 0) {
// suppress assertion message
freopen("NUL", "w", stderr);
run(aux);
}
// Undo suppression, since we are in the same process
_dup2(cstderr, _fileno(stderr));
return SIGABRT_RAISED;
#endif
}