Longest-living bug in Linux
The story of how I goofed up and nobody noticed for years.
7 May 1997
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 into
buf'. 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.