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のエラー処理でコールバック指定が出来れば良かったんだけど。。
ソースコードに手を入れてビルドし直すのは大変だからやりたくない。