Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

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... :-)

Saturday, 20 June 2009

FIBMAP ioctl example - get the file system block number of a file

The FIBMAP ioctl() is an obscure and rarely used ioctl() that returns the file system block number of a file.

To find the Nth block of a file, one uses the FIBMAP ioctl() as follows:

int block = N;
int ret = ioctl(fd, FIBMAP, &block);

where:

fd is the opened file descriptor of the file being examined,
N is the Nth block,
block is the returned file system block number of the Nth block.

fibmap.c
is example of a program that interrogates all the blocks of a file and dumps them out to stdout. From this one can see if a large file is contiguously allocated on your filesystem. One needs to have super user priviliges to be able to perform the FIBMAP ioctl, so run it using sudo. Any ideas for a good use of this ioctl() are most welcome!

UPDATE:

An alternative way to observe the output from fibmap is to use hdparm:

sudo hdparm --fibmap /initrd.img

/initrd.img: underlying filesystem: blocksize 4096, begins at LBA 63; assuming 512 byte sectors
byte_offset begin_LBA end_LBA sectors
0 860223 868414 8192
4194304 14114879 14122334 7456
 
Also check out the fiemap ioctl() for getting extent information from a file's inode.