Sunday, May 27, 2007

How things go wrong.

I've been thinking; and thinking out loud.... "Why do things go wrong?"

Things go wrong almost all the time, and with many things. Work, people, tasks, relationships, food, etc.... they all have their share of problems. They all have their reasons. For example, if we take food, then things can go wrong if you take the wrong proportion of something, or miss something out, or forget you have something on the stove(while you show your guests around), and so on. With relationships, things can go wrong if you are expecting something else that what the other person is, or if you are betrayed, or if you overly trust the other person, and he/she doesn't live up to it, and so on. Actually, the last is a commonly occurring special case of the one before it.

With work on the other hand, all of the above, plus it's own set of problems have to be dealt with. You have lots of forces at work, namely: food, inter personal relationships, people; including peers, subordinates, bosses, boss' boss, boss' boss' boss, and so on, and so forth. Additionally, you have your tasks(the least important of all????) to complete. I work in the software industry, where we deal with code and the like. Our day typically relies on copy-pasting other people's code and changing the name to our own writing lots of lines of code, and then testing it's correctness. We got to do this day in and day out with twitching, squeaking, or otherwise complaining about the inhumane working conditions such as air-conditions, free tea/coffee(that tastes almost the same), flexible-working hours(which entrust us with how long we want to work), and so on.

Let's consider a typical thing going wrong in a typical piece of code on a typical working day. The task at hand is to write a function that returns the file name given an open file descriptor to that file. Suppose we have written that function, and it's signature is:
int file_name_from_fd(int fd, char *buff, int buff_size);
Let's consider that all buffer-overflow problems in the function fine_name_from_fd have been taken care of.

The following piece of code is now written by the programmer:

int main()
{
char buff[4096];
int fd = open("/home/dhruv/data.dat", O_RDONLY);
file_name_from_fd(fd, buff, 4096);
printf("The file to FD %d is %s.\n", fd, buff);
return 0;
}

Now, is this piece of code fine, or is there something missing?

If you think it's fine, think again.... There are so many things that could go wrong. Instead of pointing them all out, I'd like to show you by writing code that handles them all(well, almost all).

int main()
{
char buff[4096];
int fd = open("/home/dhruv/data.dat", O_RDONLY);

/* Check for open() error. */
if (fd < 0) exit(1);

/* Pass buffer size 1 less than maximum size, so that
* you can write out a terminating NULL character in
* case of a full buffer.
*/
int ret = file_name_from_fd(fd, buff, 4095);

/* Check for error. */
if (ret < 0) exit(2);

/* Write out the NULL character. Will come in useful
* if ret == 4095.
*/
buff[4095] = '\0';

printf("The file to FD %d is %s.\n", fd, buff);
return 0;
}


Now, only if we all were not in such a big hurry, and took time out think things through before doing them, or at least did them well while we were at it, our lives, and those of our fellow programmers would be much less bug-ridden.

2 comments:

Anonymous said...

dude ... don't call a function for the heck of it :) .... check if the filename returned actually matches the one it intended to match :) ... only checking the return value is another bug ;).

dhruv said...

We assume that the return value indicates success or failure. And by success I mean that it gave the correct file name.
In an actual production environment, we wouldn't get the file name from FD if we already knew it.