Skipping Division by Zero on Linux

Typically, if you get a division by zero in your C program, the CPU will throw a CPU Exception which gets handled by your operating system which then kills your application.

There might be situation where you don’t want your program to get exited but instead want the div instruction to be skipped and the program continued. This posts shows how this can be achieved on Linux and X64.

Signal Handlers

The behaviour on Divison By Zero can be changed by registering a so called Signal Handler which gets called by the operating system instead of killing your application. The SIGFPE signal is emitted by the kernel and needs to be handled by your application.

Skipping Instructions

You can get the runtime information (context) of the thread which was halted because of the exception. This context-information contains the so-called programm counter (or instruction pointer) which needs to be advanced by 2 to skip the instruction.

Putting It All Together

#define _GNU_SOURCE 1
 
#include <signal.h>
#include <stdio.h>

void signal_handler (int signo, siginfo_t si, void data) {
ucontext_t uc = (ucontext_t ) data;
 
switch (signo) {
case SIGFPE:
printf("Caught FPE\n");
//Advance the Program Counter by one instruction
uc->uc_mcontext.gregs[REG_RIP]+=2;
break;
default:
printf("default handler\n");
}
}
 
int main() {
//Register Signal-Handler
struct sigaction sa, osa;
sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = signal_handler;
sigaction(SIGFPE, &sa, &osa);
 
//Produce Division By Zero
int x = 10;
int y = 0;
 
int a = 42;
 
//Here it happens
a = x / y;
 
printf("%d\n", a);
printf("Program continues\n");
 
return 0;
}

Limitations

This code only runs on X64. On other architectures, the instruction-pointer is stored in other registers and needs to be advanced by other values. Nevertheless it should be possible to port this code to other architectures.

References

Parts of the code are from a post on “Madalika’s scratchpad” which contained a solution for SPARC. I modified it to run on X64.