Tuesday 14 July 2009

Abusing C for fun

I'm easily amused by the way people can abuse C. Duff's device is a classic example of abusing the C grammar for an optimisation hack. Basically Duff unrolled a loop and realised he could interlace a switch statement into it to jump into the loop and fall through the rest of the memory copy statements:

send(to, from, count)
register short *to, *from;
register count;
{
register n=(count+7)/8;
switch(count%8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n>0);
}

So, inspired by this madness, I conjured up my own switch statement abuse, this time to show that one can get away without using break statements in a switch by abusing the while loop and continue statements. It's an ugly abuse of C:

void sw(int s)
{
switch (s) while (0) {
case 0:
printf("zero\n");
continue;
case 1:
printf("one\n");
continue;
case 2:
printf("two\n");
continue;
default:
printf("something else\n");
continue;
}
}

The while (0) statement makes one think that the code won't be executed, however the outer switch statement essentially jumps control to the case statements and the continue jumps out to the end of the loop which then never re-iterates. Urgh.

Well, I posted this discovery to comp.lanc.c in 2005 only to be trumped by this ingenious abuse of the switch statement:

int main(int argc, char **argv)
{
int a = atoi(argv[1]), b = atoi(argv[2]);

switch(a) while(0) {
case 1:
printf("case 1 of outer switch\n");
break;
case 2:
printf("case 2 of outer switch\n");
switch(b) {
case 1:
printf("case 1 of inner switch\n");
break;
case 2:
printf("case 2 of inner switch\n");
continue;
}
printf("end of inner switch\n");
break;
}
printf("end of outer switch\n");

return 0;
}

This masterpiece(?) above allows one to break out of either of two nested switch statements without a goto. I will leave this as an exercise to the reader to figure out how this works! Thanks to Richard Tobin who posted that follow up code snippet on comp.lang.c too.

So while GCC happily accepts this valid C grammar fortunately we won't be seeing code like this entering the kernel because kernel hackers are far too sensible... :-)

No comments:

Post a Comment