October, 2008

  • The Old New Thing

    Man, this housing downturn is hitting everyone

    • 12 Comments

    Consider this house on Mercer Island, which happens to be for sale. Asking price: A shade under $35 million. Five bedrooms, nine bathrooms, over 22 thousand square feet, two swimming pools, space to park a 140-foot yacht, and an interior so opulent you'd be afraid to touch anything. If you were even allowed anywhere near it.

    But the sagging economy has taken its toll on this house. They were originally asking $40 million.

    Best line from the article:

    "But we decided we might want to simplify a little, and move to Medina."

    For those who aren't familiar with Seattle-area geography, Medina is the quiet little town which has the modest homes of simple people like Bill Gates.

  • The Old New Thing

    Sucking the trap frame out of a kernel mode stack trace

    • 5 Comments

    If you are placed in the unfortunate position of having to debug a user-mode crash from kernel mode, one of the first things you have to do is get back to the exception on the user-mode side so you can see what happened. We saw earlier how you can get symbols for operating system binaries to help you suck the exception pointers out of a user-mode stack trace; here's a corresponding tip for the kernel-mode side.

    Your stack trace will look something like this:

    ChildEBP RetAddr  Args to Child
    8fc86660 818844e3 83811e00 83811d78 83811e30 nt!KiSwapContext+0x26
    8fc8669c 8184abd2 83811d78 00000000 83811d78 nt!KiSwapThread+0x3d2
    8fc866fc 81a690b1 8fc86740 00000000 00000000 nt!KeWaitForSingleObject+0x414
    8fc8681c 81a6a5aa 90a06108 83811d78 8fc86860 nt!DbgkpQueueMessage+0x283
    8fc86844 819e3cbd 8fc86860 80000003 00000000 nt!DbgkpSendApiMessage+0x44
    8fc86908 8183c542 8fc86cf0 00000001 00000000 nt!DbgkForwardException+0xd0
    8fc86cd4 8184e51a 8fc86cf0 00000000 8fc86d44 nt!KiDispatchException+0x2ee
    8fc86d3c 8184e4ce 063fedc8 75b9b7df badb0d00 nt!CommonDispatchException+0x4a
    8fc86d44 75b9b7df badb0d00 00000000 00000000 nt!KiExceptionExit+0x186
    063fedc8 75b963ea 4eedcfb0 4f370fb0 063ff0bc ABC!Control::Character::OnDestroy+0xbc
    063ff020 747d3782 4f370fb0 5665cf68 063ff0bc ABC!Control::Character::MessageHandler+0x476
    063ff034 747d3819 063ff0bc 063ff050 747d37f6 DEF!EventGizmo::FireEvent+0xf
    063ff040 747d37f6 063ff0bc 0000000c 063ff0a8 DEF!Gizmo::CallStubEvent+0x1a
    063ff050 747d3842 4f370fb0 063ff0bc c6db9237 DEF!Callback::CallOnEvent+0x19
    063ff0a8 747d6ed0 4f370fb0 063ff0bc 00000001 DEF!Callback::Invoke+0x20
    063ff0d0 747d7708 4f370fb0 00000001 4eedcfb0 DEF!Callback::FireDestroy+0x2a
    063ff0f0 747d728a 3618af68 4eedcfb0 747d7429 DEF!ObjectManager::DestroyAllChildren+0x34
    063ff0fc 747d7429 4a1bff78 4eedcfb0 747d6e9d DEF!ObjectManager::BeginDestroy+0x2e
    063ff108 747d6e9d 4eedcfb0 747d7721 4a1bff78 DEF!ObjectManager::Destroy+0x1a
    

    The third parameter to KiDispatchException is the trap frame. Most people who write about KiDispatchException do so in the context of driver debugging, but trap frames are also used during user-mode-to-kernel-mode transitions.

    0: kd> .trap 8fc86d44
    ErrCode = 00000004
    eax=00000001 ebx=00000001 ecx=4e62e594 edx=00000000 esi=5665cf68 edi=5630eff8
    eip=75b9b7df esp=063fedb4 ebp=063fedc8 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
    ABC!Control::Character::OnDestroy+0xbc:
    001b:75b9b7df 8b01            mov     eax,dword ptr [ecx] ds:0023:4e62e594=?????
    ???
    

    And there you have it, the original exception.

  • The Old New Thing

    Strange things happen when you let people choose their own name, part 3

    • 24 Comments

    Although Microsoft employees are internally assigned a cryptic email address by the IT department, the email address used for mail to and from the outside world is open to customization, to some degree.

    For example, consider an imaginary employee named Christopher Columbus. Christopher might be assigned an email address like chrisco or chriscol or ccolum or possibly the Slavic-sounding chrco. But Christopher has the option of choosing the external email address: When he sends a message to somebody outside Microsoft, the "From" line will show the external address, and if somebody from outside Microsoft sends mail to the external address, it will get routed to Christopher.

    When you choose your external name, you have a few options. The most basic version consists of your first and last name, separated with a dot: Christopher.Columbus∂microsoft.com. You can include your middle name or initial, to distinguish you from other people who have the same name: Christopher.Q.Columbus∂microsoft.com. There are other possibilities, like using your nickname or initials instead of your legal name, but that's the basic idea. There is one final option: Don't have separate external and internal email addresses; just use your internal email address for both.

    I had a brief conversation with somebody who, as it happened, encountered a bug in the tool that lets you choose your external email address. This person wanted something fairly standard like Robin.Williams∂microsoft.com but for reasons not worth going into since they're not important to the story, a bug in the system ended up assigning the external address Robin.Robin∂microsoft.com. (Note: Not Robin's real name, so don't try sending to it.)

    The IT department fixed the bug, but Robin decided to keep the erroneously-assigned email address. I'm somewhat jealous: It's not often that a database glitch ends up giving you a cool email address.

  • The Old New Thing

    Strange things happen when you let people choose their own name, part 2

    • 29 Comments

    I described last time how most parts of your entry in the company address book are closely regulated, but the differentiator is left to the honor system. Here are two and a half more examples of people who decided to do something funny with their bonus text.

    A message was sent to a mailing list I happen to be a member of, and the sender's name was listed as "John Doe (O|||||O)". I told John that I though the (O|||||O) was hilarious, and he wrote back, "Also, call my phone and listen to how the autobot says my name."

    I did, of course. The text to speech synthesizer pronounced his name as John Doe overtical bracket vertical bracket vertical bracketo.

    Number two: Lee Holmes, PowerShell blogger extraordinaire, uses as his differentiator a PowerShell prompt. He shows up in the address book as "Lee Holmes (PS C:\> _)". Oh, and wait, it's fancier than that. The underscore blinks, albeit at a glacial rate: Every so often, Lee removes the underscore from the differentiator or adds it back.

    And here's the half: Robert Hensing changed his name in the address book to Robert Hensing (EL CONQUISTADOR) (not to be confused with the shoe). This is only half of an example because I'm not going to tell you why he chose "EL CONQUISTADOR" to go after his name. I'll leave the story for him to tell (if he feels so inclined).

  • The Old New Thing

    Strange things happen when you let people choose their own name, part 1

    • 32 Comments

    One of the things that happens when you arrive at Microsoft is you are assigned an email account, and the name of that account becomes your identity. The IT department has a set of rules which they follow to arrive at your account name, but you can petition for reconsideration if the result of their algorithm produces something you don't like.

    You have more flexibility with your display name. For example, you may commonly go by a less formal version of your legal name, or you may go by your middle name or your initials or you may choose to adopt an English name as your professional name. But even though you have flexibility here, you don't have total freedom. I doubt that a request for my name to show up in the address book as Raymond Luxury-Yacht would be approved.

    There is a third component to your name, however, that you do have much more freedom with. The official name for it is the differentiator, and it appears in parentheses after the rest of your name. Here are some common uses for this bonus text:

    NameExplanation
    John Smith (MSN)
    John Smith (NEW YORK)
    To avoid confusion with other people with the same name.
    Jane Smith (DOE) Maiden name or other name you once went by.
    John Kennedy (JFK) Another name you are commonly known by.
    Alan Smithee (MOBILE) To let people know that you are rarely in the office.

    Originally, the differentiator also was submitted for approval, but the people who were responsible for approving them must have gotten tired of wading through thousands of boring requests for approval for this and other categories of personnel record changes that used to require approval. People are now simply trusted not to choose differentiators that are offensive or misleading.

    Some people have used this new freedom for humorous purposes. One prominent member of the application compatibility team has a non-English name that people often pronounce incorrectly. For the sake of discussion, let's say his name is Lav. At first, he signed his email

    –Lav, rhymes with Dave

    After a few months, based on a suggestion from a colleague (who might have been me), he changed it to

    –Lav, doesn't rhyme with "have"

    At this point, things got silly pretty quickly. A few months later, the signature changed to

    –Lav, rhymes with orange

    The last step was changing the differentiator after his name in the address book. If you look him up, he is listed as "Lav Pivo (ORANGE)".

  • The Old New Thing

    Off-Roading The Old New Thing

    • 14 Comments

    My friend ::Wendy:: decided that going off topic in the comments to this Web site was so much fun, she didn't want to let the Ground Rules stop her. So she created the Off-Roading The Old New Thing group, where people who get a thrill out of going off topic can do so without running afoul of this Web site's Ground Rules.

    Have fun, everybody!

  • The Old New Thing

    Why can't you thunk between 32-bit and 64-bit Windows?

    • 36 Comments

    It was possible to use generic thunks in 16-bit code to allow it to call into 32-bit code. Why can't we do the same thing to allow 32-bit code to call 64-bit code?

    It's the address space.

    Both 16-bit and 32-bit Windows lived in a 32-bit linear address space. The terms 16 and 32 refer to the size of the offset relative to the selector.

    Okay, I suspect most people haven't had to deal with selectors (and that's probably a good thing). In 16-bit Windows, addresses were specified in the form of a selector (often mistakenly called a "segment") and an offset. For example, a typical address might be 0x0123:0x4567. This means "The byte at offset 0x4567 relative to the selector 0x0123." Each selector had a corresponding entry in one of the descriptor tables which describes things like what type of selector it is (can it be used to read data? write data? execute code?), but what's important here is that it also contained a base address and a limit. For example, the entry for selector 0x0123 might say "0x0123 is a read-only data selector which begins at linear address 0x00524200 and has a limit of 0x7FFF." This means that the address 0x0123:n refers to the byte whose linear address is 0x00524200 + n, provided that n ≤ 0x7FFF.

    With the introduction of the 80386, the maximum limit for a selector was raised from 0xFFFF to 0xFFFFFFFF. (Accessing the bytes past 0xFFFF required a 32-bit offset, of course.) Now, if you were clever, you could say "Well, let me create a selector and set its base to 0x00000000 and its limit to 0xFFFFFFFF. With this selector, I can access the entire 32-bit linear address space. There's no need to chop it up into 64KB chunks like I had to back in the 16-bit days. And then I can just declare that all addresses will be in this form and nobody would have to bother specifying which selector to use since it is implied."

    And if you said this, then you invented the Win32 addressing scheme. It's not that there are no selectors; it's just that there is effectively only one selector, so there's no need to say it all the time.

    Now let's look at the consequences of this for thunking.

    First, notice that a full-sized 16-bit pointer and a 32-bit flat pointer are the same size. The value 0x0123:0x467 requires 32 bits, and wow, so too does a 32-bit pointer. This means that data structures containing pointers do not change size between their 16-bit and 32-bit counterparts. A very handy coincidence.

    Next, notice that the 16-bit address space is still fully capable of referring to every byte in the 32-bit address space, since they are both windows into the same underlying linear address space. It's just that the 16-bit address space can only see the underlying linear address space in windows of 64KB, whereas the 32-bit address space can see it all at once. This means that any memory that 32-bit code can access 16-bit code can also access. It's just more cumbersome from the 16-bit side since you have to build a temporary address window.

    Neither of these two observations holds true for 32-bit to 64-bit thunking. The size of the pointer has changed, which means that converting a 32-bit structure to a 64-bit structure and vice versa changes the size of the structure. And the 64-bit address space is four billion times larger than the 32-bit address space. If there is some memory in the 64-bit address space at offset 0x000006fb`01234567, 32-bit code will be unable to access it. It's not like you can build a temporary address window, because 32-bit flat code doesn't know about these temporary address windows; they abandoned selectors, remember?

    It's one thing when two people have two different words to describe the same thing. But if one party doesn't even have the capability of talking about that thing, translating between the two will be quite difficult indeed.

    P.S., like most things I state as "fact", this is just informed speculation.

  • The Old New Thing

    The cult of PowerPoint, episode 2

    • 14 Comments

    PowerPoint is a fine presentation tool, but some people have elevated it to the level of a cult. The most recent member of the PowerPoint cult was a customer who decided to use PowerPoint in an email message.

    No, I don't mean that the customer attached a bad PowerPoint presentation to the email. I mean that the customer's email was itself a three-slide PowerPoint presentation.

    Well, not quite.

    What they actually did was create a three-slide presentation, then take screenshots of each slide and embed them in the email.

    Well, not quite.

    The screenshots were shrunk to save size. Each page from the PowerPoint presentation contained about 50 words of text. Which were very hard to read because the screenshots were shrunk.

    The PowerPoint presentation itself was a shortened form of your typical boring PowerPoint slide presentation. The first slide was an introduction to the program they were using. The second slide was a statement of the problem they were having. The third slide was a call to action for Microsoft to assist in determining why the program was having the problem.

    Thank goodness it didn't have a concluding "Any questions?" slide.

  • The Old New Thing

    Psychic debugging: Why your thread is spending all its time processing meaningless thread timers

    • 12 Comments

    I was looking at one of those "my program is consuming 100% of the CPU and I don't know why" bugs, and upon closer investigation, the proximate reason the program was consuming 100% CPU was that one of the threads was being bombarded with WM_TIMER messages where the MSG.hWnd is NULL. The program was dispatching them as fast as it could, but the messages just kept on coming. Curiously, the LPARAM for these messages was zero.

    This should be enough information for you to figure out what is going on.

    First, you should refresh your memory as to what a null window handle in a WM_TIMER message means: These are thread timers, timers which are associated not with a window but with a thread. You create a thread timer by calling the SetTimer function and passing NULL as the window handle. Thread timer messages arrive in the message queue, and the DispatchMessage function calls the timer procedure specified by the message LPARAM. If the LPARAM of a thread timer message is zero, then dispatching the message consists merely of throwing it away. (If there were a window handle, then the message would be delivered to the window procedure, but there isn't one, so there's nothing else that can be done.)

    The program was spending all its time retrieving WM_TIMER messages from its queue and throwing them away. The real question is how all these thread timers ended up on the thread when they don't do anything. Who would create a timer that didn't do anything? And who would create dozens of them?

    One of the more common patterns for creating a window timer is to write SetTimer(hwnd, idTimer, dwTimeout, NULL). This creates a window timer whose identifier is idTimer. Since the timer procedure is NULL, the WM_TIMER message is dispatched to the window procedure, which in turn will have a case WM_TIMER statement followed by a switch (wParam) to handle the timer message.

    But what if hwnd is NULL, say because you forgot to check the return value of a function like CreateWindow? Well, then you just created a thread timer by mistake. And if you make this mistake several times in a row, you've just created several thread timers. Now you might think that the code that created the thread timer by mistake will also destroy the thread timer by mistake when it finally gets around to calling KillTimer(hwnd, idTimer) and passes NULL for the hwnd. But it doesn't.

    One reason is that in many cases, it's the timer that turns itself off. In other words, the KillTimer happens inside the WM_TIMER message handler. But if the WM_TIMER message isn't associated with that window, then that window procedure never gets a chance to turn off the timer.

    Another reason is more insidious. Recall that the idTimer parameter to the SetTimer function is ignored when you create a thread timer. Since you can't predict what other thread timers may exist, you can't know which timer identifiers are in use and which are free. Instead, the SetTimer function creates a unique thread timer identifier and returns it, and it is that timer identifier you must use when destroying the thread timer. Of course, the code that accidentally created the thread timer thought it was creating a window timer (which uses the timer identifier you specify), so it didn't bother saving the return value. Result: Thread timer is created and becomes orphaned.

    The machine I was asked to look at was running a stress scenario, so it was entirely likely that a low memory condition caused a function like CreateWindow to fail, and the program most likely neglected to check the return value. I never did hear back to find out if that indeed was the source of the problem, but seeing as they didn't come back for more help, I suspect I put them on the right track.

  • The Old New Thing

    Possessed: A documentary about hoarding

    • 19 Comments

    I found Possessed, a short documentary on hoarders, fascinating because I teeter on the brink of hoarding myself and have to fight it. Some days I am more successful than others. Notice how coherently the subjects talk about their obsession. They know it's pathological, but they can't stop themselves.

    I was able to beat my hoarding of cardboard boxes ("Hey, it'd be a waste to toss these cardboard boxes into the recycle bin; I could re-use it someday, like maybe if I have to mail a package or something") when a friend of mine was moving and needed cardboard boxes to pack up his things. I gladly handed over my stash of cardboard boxes, with the instructions that when he was finished, the cardboard boxes were his problem. That solved two problems. I was able to get rid of my cardboard boxes with a clear conscience, and my friend got a bunch of moving boxes.

Page 2 of 4 (33 items) 1234