Longest-living bug in Linux

quoted from http://liw.iki.fi/liw/texts/longest-living-bug.html

In the spring and summer of 1991, my friend Linus was playing around with this OS-like program, which later became Linux. He wanted a printf like service inside the kernel, but didn’t know how to implement it, though (he didn’t know C thoroughly back then). So I wrote him an sprintf clone, and he used that, after some modifications.

In September of 1994, Friedemann Baitinger at IBM, who was developing a device driver for another operating system, used my sprintf clone as a debugging aid (but not in the final product). The bug lived for three or three and a half years before anyone found it. Worse, the bug was immediately obvious as soon as one tried to use the function in a certain, common way. No-one had done that, ever, not even I when I wrote it. Don’t ever hire me to write code that is expected to work.

The bug was in the handling of a field width given via the argument list. With sprintf, to print a string, for example, you would write

sprintf(buf, "%s", str);

This would put the str' string intobuf’. sprintf allows formatting of the output:

sprintf(buf, "%10s", str);

This would make the output string at least 10 characters wide (wider, if `str’ is wider). The field width can be a constant, or it can be given as a separate argument:

sprintf(buf, "%*s", 10, str);

This gives the same output as before, but triggered my bug.

My sprintf was implemented with a loop that walked through the format string and incremented an index when it processed various parts of the format string. Except that when it processed the `*’, it didn’t increment. Oops.

So why do I explain this so thoroughly? My weird sense of humor made me put “Author of the longest-living Linux bug” in the CREDITS file in the kernel sources, and people sometimes ask me about it. I figured I’d answer it once, and point people at this web page.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *