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