signal
http://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/sig-1.html
に書かれていたコードが参考になったけど二回目のCtrl+Cを受け付けてくれないので、
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> #include <unistd.h> jmp_buf JumpBuffer; void INThandler(int); int main(int argc, char* argv[]) { signal(SIGINT, INThandler); while (1) { if (sigsetjmp(JumpBuffer, 1) == 0) { printf("Hit Ctrl-C at anytime ... \n"); pause(); } } return 0; } void INThandler(int sig) { signal(sig, SIG_IGN); char c; printf( "OUCH, did you hit Ctrl-C?\n" "Do you really want to quit? [y/n] "); c = getchar(); if (c == 'y' || c == 'Y') { exit(0); }else { while ((c = getchar()) != '\n' && c != EOF) ;/* discard */ signal(SIGINT, INThandler); siglongjmp(JumpBuffer, 1); } }
のように改造した。
調べたところ、signal より sigaction を使うべき事が分かった。
#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> #include <unistd.h> #include <memory.h> #include <stdbool.h> jmp_buf JumpBuffer; static void ILLaction(int sn , siginfo_t* si , void* sc) { const void* addr = si->si_addr; static const size_t len = 64; static const void* s_addresses[len]; bool found = false; for (size_t i=0; i<len; ++i) { if (s_addresses[i] == addr) { found = true; break; } } if (!found) { for (size_t i=0; i<len; ++i) { if (s_addresses[i] == 0) { s_addresses[i] = addr; printf("%p\n", addr); break; } } } siglongjmp(JumpBuffer, 1); } static void regist_sa() { struct sigaction sa_sigill; memset(&sa_sigill, 0, sizeof(sa_sigill)); // sa_sigill.sa_handler = ILLhandler; sa_sigill.sa_sigaction = ILLaction; sa_sigill.sa_flags = SA_SIGINFO; sigaction(SIGILL, &sa_sigill, (struct sigaction *)NULL); } /* -fsanitize=integer,unsigned-integer-overflow,shift \ -fsanitize-undefined-trap-on-error \ */ int test(int a, int b) { int add = a + b; int sub = a - b; int mul = a * b; int div = a / b; return mul; } int main(int argc, char* argv[]) { regist_sa(); for (int i=0; i<3; ++i) { int a; int b; if (sigsetjmp(JumpBuffer, 1) == 0) { printf("input\n"); char buff[256]; fgets(buff, 256, stdin); sscanf(buff, "%d %d", &a, &b); int c = test(a, b); printf("%d\n", c); }else { printf("err : %d %d\n", a, b); } } return 0; }
シグナル発生元に戻して次のインストラクションに進めるとかはきっぱりと諦める。
clangとcompiler-rtのubsanのエラー処理でコールバック指定が出来れば良かったんだけど。。
ソースコードに手を入れてビルドし直すのは大変だからやりたくない。