December, 2009

  • The Old New Thing

    Exploiting the inattentive: The posted wine rating may not match the wine on the shelf

    • 7 Comments

    The Washington Post did a spot check of area wine stores and found that of the "shelf talkers" signs (those things that describe the wine and tell you what score it received from Wine Spectator magazine) it found, a quarter of them were incorrect, usually by attributing a good score to the correct wine vineyard but from a different year. So when you cruise the wine store, make sure to double-check that the information placard actually matches the wine it's posted next to.

  • The Old New Thing

    Why is it possible to destroy a critical section while it is in use?

    • 15 Comments

    Some time back, Stu wondered why it is possible to destroy a critical section while it is in use.

    Well, there's nothing stopping you from creating a file that contains these lines:

    #include <windows.h>
    int __cdecl main(int, char**)
    {
      CRITICAL_SECTION cs;
      InitializeCriticalSection(&cs);
      EnterCriticalSection(&cs);
      DeleteCriticalSection(&cs);
      return 0;
    }
    

    and then telling your compiler to turn it into a program. It's not like a bolt of lightning is going to come out of the sky and zap you before you hit the Enter key.

    So obviously, it's possible.

    On the other hand, it's a bug, just like closing a handle to a file that another thread is reading from, or like closing an event handle that another thread is waiting on.

    Critical sections are one of those low-level I sure hope you know what you're doing because I'm not going to help you if you mess up pieces of functionality. If you use them incorrectly, then you will suffer the consequences, the same as if you tried to free memory twice or write to memory after freeing it or cast a Gdiplus::Color* to a CComBSTR*.

    Are there any legitimate cases where you would delete a critical section while it is owned? I sure can't think of any.

    If there were a legitimate case for deleting a critical section while it is owned, what could it be? Well, it can't be owned by the thread doing the deleting, because that would imply that you took it in order to prevent somebody else from entering it (while you deleted it), but that just creates another race condition: If you tinker the timing, then you can create this scenario: That other thread gets pre-empted just as it was about to execute the first instruction of the EnterCriticalSection function. Meanwhile, the destroying thread enters the critical section, does whatever other stuff it wants to do, and then deletes the critical section. That other thread finally gets a chance to run and is now attempting to enter a deleted critical section, which is clearly not legal.

    Okay, so if there were a legitimate case, it would have to be deleting a critical section owned by some other thread. Maybe that other thread enters the critical section, and then signals the main thread to delete the critical section. Why would it do that? Who knows. Maybe it wants to make sure only one thread signals the main thread. But you still have the same problem as with the previous case: You entered the critical section because you wanted to prevent a third thread from entering the protected region, but that third thread might have been pre-empted just as it transferred control to the first instruction of EnterCriticalSection, and when that third thread finally gets some CPU time, it proceeds to enter a deleted critical section.

    So I can't think of a legitimate reason for deleting a critical section while it's in use. Maybe there's a flaw in my logic.

  • The Old New Thing

    Tweeting Too Hard: Best of Twitter

    • 5 Comments

    We had Best of Craig's List.

    We had Lamebook.

    Now we have Tweeting Too Hard, "where self-important tweets get the recognition they deserve."

    Examples:

    The people who say I'm arrogant and shallow don't see me when I'm at home with my wife. Did I mention that she's a former swimsuit model?
    How was it I got invite to last yrs White House Xmas party when Bush was prez; and nothing this year? I guess I must try harder 2 be fab.
  • The Old New Thing

    No, you can't lock icons to the user's desktop

    • 28 Comments

    In another installment of I bet somebody got a really nice bonus for that feature, I submit this question for your consideration.

    My customer wants to know how to lock a specific icon to the upper left hand corner of the desktop.

    This company must be writing the most awesome program to end all programs, a program so amazingly awesome that it should appear as the very first thing on the desktop so you won't forget how awesome it is.

    I think their users may disagree with that assessment.

    And the answer is, no, there is no supported way to force a particular icon to appear at a particular desktop position.

  • The Old New Thing

    Christmas gift idea for your favorite Microsoft fanboy geek with no sense of fashion or taste

    • 8 Comments

    Then again, the "no sense of fashion or taste" may be redundant.

    Perhaps you are so enamored of the Microsoft-branded Snuggie you received at the Company Meeting that you can't keep your excitement to yourself and want to share the joy with a friend. No problem. You can now pick one up at the Microsoft Company Store in Redmond, right across the hall from the Visitor Center. (The Rapture Index ticks up another notch.)

    "You shouldn't have."

    Previously, in Christmas gift ideas.

  • The Old New Thing

    What version of the compiler does Raymond use?

    • 18 Comments

    From the suggestion box, BrianK asks, "What compiler do you and other developers use? Are you using VS2005 yet?"

    To be honest, I don't know what compiler I use.

    There is a separate part of the team that worries about things like "What compiler should we use?" They deal with nitty-gritty details like "What version of the compiler should we use and what optimizations should we enable?" as well as higher-level planning like "How are we going to organize our source code so that different parts of the project can take advantage of each others' work while still not requiring all members of the Windows team to compile the entire operating system from scratch when they want to test their changes?"

    I am not a member of that team, nor am I invited to their meetings, nor would I be interested in attending their meetings. I'm perfectly happy to let them make these decisions. They pick a compiler version and add it to the toolset that gets installed to your computer when you enlist in the Windows project. That way nobody needs to care what version, service pack, and patch number of the compiler they need to obtain. It just comes with the development environment.

    As I've noted in an earlier column in TechNet Magazine, the operating systems division will at times call upon the languages division to produce a special not-found-in-nature version of the compiler in order to satisfy a specific need. Windows (at least the 32-bit version) contains a 16-bit emulator and a miniature copy of 16-bit Windows. Since no modern version of Visual Studio targets 16-bit Windows any more, the compilers that the Windows team uses for 16-bit Windows necessarily must come from somewhere else.

    Changing the compiler version is a risky operation, because doing so will most likely expose subtle bugs in the code which erroneously relied upon unspecified behavior, such as order of evaluation or the location of memory barriers. Not the sort of thing you want to spring on a project one week before pencils down. Yes, if all the code were written perfectly, then this wouldn't be a problem. But few people write perfect code.

    (And just as a favor to you, I dug through the source code history for Windows and requested the 32-bit native compiler that was in use on August 28, 2006. And then I extracted the version strings and compared it to the version strings that came with Visual Studio 8, and they seemed to match. So I guess it's Visual Studio 8. What relationship that has to VS2005 I don't know.)

  • The Old New Thing

    The economic inefficiency of gift-giving

    • 19 Comments

    Economist Joel Waldfogel explains why gift-giving is bad for the economy, and why a charity gift card is the best luxury gift of all.

    He goes into more detail in his new book, Scroogenomics, which you can buy somebody for Christmas just to tell Waldfogel where he can stick it. ("In the bank!" he'll say as he heads out with his royalty check.)

    Related: Economist Tim Harford writes an advice column called Dear Economist for the Financial Times. But instead of applying economic theory to economic problems, he applies economic theory to personal problems.

    As Harford himself explains, "Every advice columnist needs a persona, and for Dear Economist it was blunt, rude, and rather fond of the latest economic research."

  • The Old New Thing

    I got an array with plenty of nuthin'

    • 24 Comments

    A customer reported a memory leak in the function PropVariantClear:

    We found the following memory leak in the function PropVariantClear. Please fix it immediately because it causes our program to run out of memory.

    If the PROPVARIANT's type is VT_ARRAY, then the corresponding SAFEARRAY is leaked and not cleaned up.

    SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
    PROPVARIANT v;
    v.vt = VT_ARRAY;
    v.parray = psa;
    PropVariantClear(&v);
    
    // The psa is leaked
    

    Right now, we are temporarily working around this in our program by inserting code before all calls to PropVariantClear to free the SAFEARRAY, but this is clearly an unsatisfactory solution because it will merely result in double-free bugs once you fix the bug. Please give this defect your highest priority as it is holding up deployment of our system.

    The VT_ARRAY value is not a variant type in and of itself; it is a type modifier. There are other type modifiers, such as VT_VECTOR and VT_BYREF. The thing about modifiers is that they need to modify something.

    The line v.vt = VT_ARRAY is incorrect. You have to say what you have a safe array of. In this case, you want v.vt = VT_ARRAY | VT_UNKNOWN. Once you change that, you'll find the memory leak is fixed.

    The customer didn't believe this explanation.

    I find this doubtful for several reasons.

    1. While this would explain why the IUnknowns in the SAFEARRAY are not released, it doesn't explain why the SAFEARRAY itself is leaked.
    2. The SAFEARRAY already contains this information, so it should already know that destroying it entails releasing the IUnknown pointers.
    3. If I manually call SafeArrayDestroy, then the IUnknowns are correctly released, confirming point 2.
    4. The function SafeArrayDestroy is never called; that is the root cause of the problem.

    The customer's mental model of PropVariantDestroy appeared to be that it should go something like this:

    if (pvt->vt & VT_ARRAY) {
     switch (pvt->vt & VT_TYPEMASK) {
     ...
     case VT_UNKNOWN:
      ... release the IUnknowns in the SAFEARRAY...
      break;
     ...
     }
     InternalFree(pvt->psa->pvData);
     InternalFree(pvt->psa);
     return S_OK;
    }
    

    In fact what's really going on is that the value of VT_ARRAY is interpreted as VT_ARRAY | VT_EMPTY, because (1) VT_ARRAY is a modifier, so it has to modify something, and (2) the numeric value of zero happens to be equal to VT_EMPTY. In other words, you told OLE automation that your PROPVARIANT holds a SAFEARRAY filled with VT_EMPTY.

    It also happens that a SAFEARRAY of VT_EMPTY is illegal. Only certain types can be placed in a SAFEARRAY, and VT_EMPTY is not one of them.

    The call to PropVariantClear was returning the error DISP_E_BADVARTYPE. It was performing parameter validation and rejecting the property variant as invalid, because you can't have an array of nothing. The customer's response to this explanation was very terse.

    Tx. Interesting.
  • The Old New Thing

    Surprising things injected into Mozart cadenzas

    • 18 Comments

    This review of a Seattle Symphony concert from 2007 mentioned that back in 1998, soloist Jon Kimura Parker inserted the theme from The X-Files into one of his cadenzas. Cadenzas were originally points in a concerto at which soloists could improvise and show off their technical skills, but over the years, the contents of cadenzas have become more and more rehearsed, with most composers having switched over to fully-written-out cadenzas over a hundred years ago.

    That's why it's so exciting when an improvised cadenza reappears on the scene. All of a sudden, anything can happen. Reading the article reminded me of a cadenza surprise in a performance by Awadagin Pratt nearly twenty years ago. I'm fairly certain the piece was a Mozart piano concerto, and during the cadenza, Pratt slipped into a middle voice the theme from the opening movement of the Mendelssohn Scottish Symphony, which was the next piece on the program! By the time I figured out what was happening, it was over. My opportunity to burst into applause in the middle of a piece was lost.

  • The Old New Thing

    What was the ShowCursor function intended to be used for?

    • 17 Comments

    Back in the days when Windows was introduced, a mouse was a fancy newfangled gadget which not everybody had on their machine. Windows acknowledged this and supported systems without a mouse by having keyboard accelerators for everything (or at least that was the intent). But if the design stopped there, you'd have a dead cursor in the middle of your screen all the time, which you could move around if you had a mouse, which you didn't.

    Enter the ShowCursor function.

    The ShowCursor function takes a parameter that indicates whether you want to show or hide the cursor. (It would perhaps be more verbosely named ChangeCursorShowState.) If you call ShowCursor(TRUE) then the cursor show count is incremented by one; if you call ShowCursor(FALSE) then the cursor show count is decremented by one. A cursor is show on the screen if the cursor show count is greater than or equal to zero.

    When Windows starts up, it checks if you have a mouse. If so, then the cursor show count is initialized to zero; otherwise, it is initialized to negative one. That way, you don't get an annoying immovable cursor on the screen if you don't have a mouse.

    If a program entered a state where it wanted to show the cursor even on systems without a mouse, it would call ShowCursor(TRUE) when it entered the state, and ShowCursor(FALSE) when it left it. One such state might be when activating the keyboard interface for selecting a rectangular region in a document. Under these conditions, a program naturally is expected to move the cursor around in response to user actions, even if the user didn't move the physical mouse hardware.

    But the most common reason for forcing the cursor to be shown is in order to show an hourglass cursor because it's busy. That's right, back in the mouseless days, code to display an hourglass cursor went like this:

    HCURSOR hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
    ShowCursor(TRUE); // force cursor shown on mouseless systems
    ... perform long operation ...
    ShowCursor(FALSE); // re-hide cursor on mouseless systems
    SetCursor(hcurPrev);
    

    Conversely, if a program entered a state where it wanted to hide the cursor even on systems with a mouse, it would call ShowCursor(FALSE) when it entered the state, and ShowCursor(TRUE) when it left it. For example, you might do this when showing a slide show.

    Let's look at how this all worked out in practice. I use a table because people seem to like tables.

    Machine with mouse Machine without mouse
    Normal 0 (cursor shown) -1 (cursor hidden)
    Enter mode where cursor should be forced shown
    ShowCursor(TRUE) 1 (cursor shown) 0 (cursor shown)
    Exit mode where cursor should be forced shown
    ShowCursor(FALSE) 0 (cursor shown) -1 (cursor hidden)
    Enter mode where cursor should be forced hidden
    ShowCursor(FALSE) -1 (cursor hidden) -2 (cursor hidden)
    Exit mode where cursor should be forced hidden
    ShowCursor(TRUE) 0 (cursor shown) -1 (cursor hidden)

    Now that all systems come with a mouse as standard equipment, this historical information is not of much use, but there it is in case you were wondering. (And in a case of everything old is new again, the growing popularity of touch computing means that you once again have a class of computers with no mouse. So maybe this information is useful after all. Just a fluke, I assure you.)

    Back in the old 16-bit days, this counter was a global state, along with other window manager states like the focus window and the input queue. During the conversion to Win32, the cursor show counter became a thread-local state. (Naturally, multiple threads could merge their cursor show counters by attachment.) Consequently, when a thread calls ShowCursor it affects the cursor show state only for windows that belong to that thread.

Page 2 of 4 (40 items) 1234