Holy cow, I wrote a book!
I didn't debug it personally, but I know the people who did.
During Windows XP development, a bug arrived on
a computer game that crashed only after you got to one of the higher levels.
After many saved and restored games, the problem was finally identified.
The program does its video work in an offscreen buffer and transfers
it to the screen when it's done. When it draws text with a shadow,
it first draws the text in black, offset down one and right one pixel,
then draws it again in the foreground color.
So far so good.
Except that it didn't check whether moving down and right one pixel
was going to go beyond the end of the screen buffer.
That's why it took until one of the higher levels before the bug
manifested itself. Not until then did you accomplish a mission
whose name contained a lowercase letter with a descender!
Shifting the descender down one pixel caused the bottom row of
pixels in the character to extend past the video buffer and
start corrupting memory.
Once the problem was identified, fixing it was comparatively easy.
The application compatibility team
has a bag of tricks, and one of them is called
This particular compatibility fix adds padding to every heap
allocation so that when a program overruns a heap buffer, all
that gets corrupted is the padding.
Enable that fix for the bad program
(specifying the amount of padding necessary,
in this case, one row's worth of pixels), and run through the
game again. No crash this time.
What made this interesting to me was that you had to play the
game for hours before the bug finally surfaced.
On x86 machines, Windows chooses a page size of 4K because that was the
only page size supported by that architecture at the time the operating
system was designed. (4MB pages were added to the CPU later,
in the Pentium as I recall, but clearly that is too large for everyday use.)
For the ia64, Windows chose a page size of 8K. Why 8K?
It's a balance between two competing objectives.
Large page sizes allow more efficient I/O since you are reading
twice as much data at one go. However large page sizes also
increase the likelihood that the extra I/O you perform is wasted
because of poor locality.
Experiments were run on the ia64 with various page sizes
(even with 64K pages, which were seriously considered at one point),
and 8K provided the best balance.
Note that changing the page size creates all sorts of problems
for compatibility. There are large numbers of programs out there that
blindly assume that the page size is 4K.
Boy are they in for a surprise.
Even though Windows NT uses UTC internally,
the BIOS clock stays on local time.
Why is that?
There are a few reasons.
One is a chain of backwards compatibility.
In the early days, people often dual-booted between
Windows NT and MS-DOS/Windows 3.1.
MS-DOS and Windows 3.1 operate on local time,
so Windows NT followed suit so that you wouldn't
have to keep changing your clock each time you changed
As people upgraded from Windows NT to
Windows 2000 to Windows XP, this choice
of time zone had to be preserved so that people
could dual-boot between their previous operating
system and the new operating system.
Another reason for keeping the BIOS clock on local time
is to avoid confusing people who set their time via the BIOS
If you hit the magic key during the power-on self-test,
the BIOS will go into its configuration mode, and one of
the things you can configure here is the time.
Imagine how confusing it would be if you set the time to 3pm,
and then when you started Windows, the clock read 11am.
"Stupid computer. Why did it even ask me to change the time
if it's going to screw it up and make me change it a second time?"
And if you explain to them, "No, you see, that time was UTC,
not local time," the response is likely to be
"What kind of totally propeller-headed nonsense is that?
You're telling me that when the computer asks me what time it is,
I have to tell it what time it is in
(Except during the summer in the northern hemisphere,
when I have to tell it what time it is in
Why do I have to remember my time zone and manually subtract
four hours? Or is it five during the summer? Or maybe I have to
add. Why do I even have to think about this?
Stupid Microsoft. My watch says three o'clock. I type three o'clock.
End of story."
(What's more, some BIOSes have alarm clocks built in,
where you can program them to have the computer turn itself on at a particular
time. Do you want to have to convert all those times to UTC
each time you want to set a wake-up call?)
The various Interlocked functions
(InterlockedIncrement, and so on)
require that the variable being updated be properly aligned,
even on x86, a platform where the CPU silently fixes unaligned
memory access invisibly.
If you pass an unaligned pointer to one of the Interlocked
functions, the operation will still succeed, but the result
won't be atomic. Another processor may see a partially-completed
This is a particularly insidious bug since it happens only
on multiprocessor machines under very tight timing conditions.
You will be hard-pressed to reproduce this in the laboratory.
stole my thunder and remarked on it yesterday.)
Moral of the story: Same as yesterday. Mind your alignment.
Sometimes unaligned memory access will hang the machine.
Some video cards do not let you access all the video memory at one go.
Instead, you are given a window
into which you can select which
subset of video memory ("bank") you want to see.
For example, the EGA video card had 256K of memory, split into four
If you wanted to access memory in the first 64K, you had to select
bank zero into the window, but if you wanted to access memory in
the second 64K, then you had to select bank one.
Bank-switching makes memory access much more complicated,
For example, if you want to copy a block of memory into bank-switched
memory, you have to check when you are going to cross a bank boundary
and break the copy up into pieces. If you are doing something that
requires non-sequential access
(say, drawing a diagonal line),
you have to check when your line is going to cross into another bank.
To simplify matters, Windows 95 had a driver called VFLATD
that made bank-switched memory look flat to the rest of the system.
Flattening the bank-switched memory model was also crucial for
in particular, the IDirectDrawSurface::Lock method gave you direct
access to a (seemingly) flat expanse of video memory.
For example, if the application wanted to see a 256K surface
and accessed memory in the first 64K of memory,
the VFLATD driver would select bank zero and map the 64K physical
memory window into the first 64K of the virtual 256K memory window.
This worked great as long as everybody uses only aligned memory
accesses. But if you access unaligned memory, you can send VFLATD
into an infinite loop and hang the machine.
Suppose you make an unaligned memory access that straddles two banks.
This memory access can never be satisfied.
A page fault is taken on the lower portion of the unaligned access,
and VFLATD maps the lower bank into memory.
Then a page fault is taken on the higher portion of the unaligned
access, and VFLATD now has to map the upper bank; this unmaps the
lower bank, since the video card is bank-switched and only one bank
can be mapped ata time. Now a page fault is taken on the lower portion,
and the infinite loop continues.
Moral of the story: Keep those memory accesses aligned, even on
the x86, which most people would consider to be one where it is
"safe" to violate alignment rules.
another example of how misaligned data access can create bugs x86.
If you've messed with the shell namespace, you've no doubt run across the kooky STRRET structure, which is used by IShellFolder::GetDisplayNameOf to return names of shell items. As you can see from its documentation, a STRRET is sometimes an ANSI string buffer, sometimes a pointer to a UNICODE string, sometimes (and this is the kookiest bit) an offset into a pidl. What is going on here?
The STRRET structure burst onto the scene during the Windows 95 era. Computers during this time were still comparatively slow and memory-constrained. (Windows 95's minimum hardware requirements were for 4MB of memory and a 386DX processor - which ran at a whopping 25MHz.) It was much faster to allocate memory off the stack (a simple "sub" instruction) than to allocate it from the heap (which might take thousands of instructions!), so the STRRET structure was designed so the common (for Windows 95) scenarios could be satisfied without needing a heap allocation.
The STRRET_OFFSET flag took this to an even greater extreme. Often, you kept the name inside the pidl, and copying it into the STRRET structure would take, gosh, 200 clocks (!). To avoid this wasteful memory copying, STRRET_OFFSET allowed you to return just an offset into the pidl, which the caller could then copy out of directly.
Woo-hoo, you saved a string copy.
Of course, as time passed and computers got faster and memory became more readily available, these micro-optimizations have turned into annoyances. Saving 200 clock cycles on a string copy operation is hardly worth it any more. On a 1GHz processor, a single soft page fault costs you over a million cycles; a hard page fault costs you tens of millions.
You can copy a lot of strings in twenty million cycles.
What's more, the scenarios that were common in Windows 95 aren't quite so common any more, so the original scenario that the optimization was tailored for hardly occurs any more. It's an optimization that has outlived its usefulness.
Fortunately, you don't have to think about the STRRET structure any more. There are several helper functions that take the STRRET structure and turn it into something much easier to manipulate.
The kookiness of the STRRET structure has now been encapsulated away. Thank goodness.
The "look" of the Windows user interface has gone through fashion cycles.
In the beginning, there was Windows 1.0,
which looked very flat because screen resolutions were
rather low in those days and color depth was practically nonexistent.
If you had 16 colors, you were doing pretty good.
You couldn't afford to spend very many
pixels on fluff like borders, and shadows were out of the question due
to lack of color depth.
The "flat look" continued in Windows 2.0, but Windows 3.0 added
a hint of 3D (notice the beveling in the minimize/maximize buttons
and in the toolbar buttons on the help window).
Other people decided that the 3D look was the hot new thing, and
libraries sprung up to add 3D shadow and outlining effects to
nearly everything. The library CTL3D.DLL started out as just an
Excel thing, but it grew in popularity until it became the "standard"
way to make your dialog boxes "even more 3D".
Come Windows 95,
even more of the system had a 3D look.
Notice the beveling along the inside edge of the panes in the
Furthermore, 3D-ness was turned on by default for all programs that
marked themselves as "4.0"; i.e., programs that were designed for
For programs that wanted to run on older versions of Windows as well,
a new dialog style DS_3DLOOK was added, so that they could indicate
that they wanted 3D-ization if available.
And if the 3D provided by Windows 95 by default wasn't enough,
you could use CTL3D32.DLL to make your controls
even more 3D.
By this point, things started getting really ugly.
Buttons on dialog boxes had so many heavy black outlines that
it started to look like a really bad mascara job.
Fortunately, like many fashions that get out of hand, people
realized that too much 3D is not a good thing. User interfaces
got flatter. Instead of using 3D effects and bold outlines to
separate items, subtler dividers were used.
Divider lines became more subdued and sometimes disappeared entirely.
Microsoft Office and Microsoft Money were two programs that embraced
the "less is more" approach.
this screenshot from Microsoft Money,
observe that the beveling is gone. There are no 3D effects.
Buttons are flat and unobtrusive.
The task pane separates itself from the content pane by a simple
gray line and a change in background shade. Even the toolbar has
Office 2000 also went largely flat, though some 3D effects
linger, in the grooves and in the scrollbars (not visible in picture).
Windows XP jumped on the "flat is good" bandwagon
and even got rid of the separator line between the tasks pane
and the contents pane. The division is merely implied by the
change in color.
"Separation through juxtaposition."
Office XP and
Outlook 2003 continue the trend and flatten nearly everything
aside from the scrollbar elements. Blocks of color are used
to separate elements onscreen,
sometimes with the help of simple outlines.
So now the pendulum of fashion has swung away from 3D back towards
Who knows how long this school of visual expression will hold
the upper hand.
Will 3D return with a vengeance when people tire of the starkness
of the flat look?
Back in the days of Windows 95, when
Plug and Play was in its infancy,
one of the things the Plug and Play team
did was push the PCI specification to an
They took a computer and put it at one end of a hallway.
They then built a chain of PCI bridge cards that ran down
the hallway, and at the end of the chain, plugged in a video card.
And then they turned it on.
Amazingly, it actually worked.
The machine booted and used a video
card twenty feet away. (I'm guessing at the distance.
It was a long time ago.)
It took two people to operate this computer,
one to move the mouse and type, and another to
watch the monitor at the other end and report where the pointer was
and what was happening on the screen.
And the latency was insane.
But it did work and thereby validated the original design.
Other Plug and Play trivia:
The phrase "Plug and Play" had already been trademarked at the
time, and Microsoft had to obtain the rights to the phrase
from the original owners.
Windows 98 was the first version of Windows to support
multiple monitors. And the limit was nine.
Because that allowed you to arrange your monitors
You have early seventies television to thank.
[Raymond is currently on vacation; this message was pre-recorded.]
When writing documentation, one often has need to come up with
a sample URL to illustrate some point or other.
When you do, make sure the sample URL is under your control.
I remember a Windows beta that used the sample URL
http://www.xxxxx.com/ in a dialog box.
You can imagine where that actually goes.
This web site uses www.wallyworld.com as a sample URL.
Perhaps they didn't realize that it's a gay porn site.
(Raymond's strange dream story: One night I dreamt that I found
a web site that had a complete Dilbert
archive, and for some reason the name of the site was
World". In the morning, I checked out the site and was in for a big
So play it safe. When you need a sample URL, don't just make something
up. If you do, odds are good that somebody is going to rush in and
register it. Make your sample URLs point back to your company's
home page, or use
http://www.example.com, which the IANA
has reserved for use in sample URLs.
If that's too dorky, you can always go out and register the domain
you want to use as your sample, so that nobody else can sneak in and
steal it. (This does have the problem of incurring renewal fees.)