• The Old New Thing

    Sometimes the bug isn't apparent until late in the game


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

  • The Old New Thing

    Why is the page size on ia64 8K?


    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.

  • The Old New Thing

    Why does Windows keep your BIOS clock on local time?


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

    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 itself. 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 London? (Except during the summer in the northern hemisphere, when I have to tell it what time it is in Reykjavik!?) 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 Old New Thing

    Importance of alignment even on x86 machines, part 2


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

    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.

    (A commenter stole my thunder and remarked on it yesterday.)

    Moral of the story: Same as yesterday. Mind your alignment.

  • The Old New Thing

    Importance of alignment even on x86 machines


    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 64K banks. 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 DirectDraw support; 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.

    Next time, another example of how misaligned data access can create bugs x86.

  • The Old New Thing

    The kooky STRRET structure


    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 Old New Thing

    The evolution of mascara in Windows UI


    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 Explorer window. Furthermore, 3D-ness was turned on by default for all programs that marked themselves as "4.0"; i.e., programs that were designed for Windows 95. 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. In 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 gone flat. 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 flatness. 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?

  • The Old New Thing

    A twenty-foot-long computer


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

    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.

  • The Old New Thing

    Why was nine the maximum number of monitors in Windows 98?


    Windows 98 was the first version of Windows to support multiple monitors. And the limit was nine.

    Why nine?

    Because that allowed you to arrange your monitors like this. You have early seventies television to thank.

    [Raymond is currently on vacation; this message was pre-recorded.]

  • The Old New Thing

    Watch out for those sample URLs


    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 "Wally World". In the morning, I checked out the site and was in for a big surprise...)

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

Page 39 of 50 (499 items) «3738394041»