If you thought my previous post showed how ugly computing could be, you ain’t seen nothing yet. Recently, I had occasion to look into how to catch integer overflows in kernel code. I won’t go into a lot of detail about why, except to point out that it takes a bit less than a month for a millisecond timer stored in a signed 32-bit integer to wrap around. It didn’t take long to discover gcc’s -ftrapv option, which generates signals if an overflow is detected, but there are a couple of problems with that. One is that enabling the option causes gcc to use functions for integer arithmetic operations, which is pretty seriously bad for performance. The other is that these functions don’t exist in the kernel (or embedded system) and neither do any of the functions to throw/catch signals. I get pretty tired of “the whole programming world is like the easy user-space stuff I do” attitudes sometimes, but that’s a rant for another time. I needed something that was reasonably efficient and could be used from the kernel. To do that, I had to resort to inline assembly, and gcc’s syntax for that has to be one of the ugliest things I’ve seen in computing. In any case, here’s what I came up with for x86 multiplication.

// Overflow-catching equivalent of "var *= num;"
#define MUL_OVF(var,num,lbl,dum) asm( \
    "imull %2\n"                      \
    "\tjno "#lbl"\n"                  \
    "\tint3\n"                        \
    #lbl":"                           \
    :"=a"(var), "=d"(dum)             \
    :"rm"(num), "0"(var));

Yeah, it’s pretty nasty, and it’s even nastier so it can be general; the lbl and dum arguments only exist so that I can use the macro multiple times within one function and use spare variables instead of making up new ones respectively. (I’d normally recommend creating a separate variable anyway for the sake of clarity, and letting the compiler’s register allocator deal with it, but when inline assembly is involved things get trickier.) Basically all this does is perform the multiplication and then trip a breakpoint if it overflowed. There’s a bit of a potential instruction-pipeline bubble because of the jump, so this doesn’t come for free, but it’s still a lot cheaper than calling a function. It would take a little more effort to write a similar macro that does something besides breakpoint, like perhaps call a function to print out a stack trace, but in a development environment the macro above (or similar for addition and subtraction) should be sufficient.