• The Old New Thing

    The invisible price reduction

    • 17 Comments

    Swedish discount warehouse chain Coop Forum is running an advertising campaign claiming "New Lower Prices!", but how can you tell? Apparently you're not supposed to (shocking!) compare current prices against what they were before the ad campaign.

    Raymond's bad translation follows.

    Coops "new" price reduction not new

    A major new price reduction advertising campaign issued by discount warehouse chain Coop Forum this week to all households in the Stockholm area could be misleading.

    The list of which merchandise which actually had their prices lowered, that is secret, according to Roger Gehrman, vice managing director for Coop Forum.

    "The price structure is one of the probably most important trade secrets we have," he says.

    But you claim that you are lowering prices. How can one be sure that you really are doing it?

    "You can't compare today's prices with how they were earlier," says Roger Gehrman.

    Difficult to know for both Ica and Coop

    It is almost just as hard to get a grasp on Coop's claimed price reduction as it is with Ica's.

    Ekot's check shows that both chains refuse to show which individual items were lowered or how large individual price reductions are.

    Don't want to report which items were reduced

    Coop's manager Roger Gehrman doesn't even want to state which product categories were reduced the most.

    "I don't want to go into that. It is nearly all of our product range but I don't have detailed knowledge to talk about a specifically reduced product and I don't have the list in front of me either," he says.

    This week's advertising flyer from Coop Forum to households in the Stockholm region are misleading. "Welcome to our largest price reduction ever" and "New lower prices" says the discount warehouse chain now about a price reduction which in the Stockholm area was already put into place last autumn.

    "It happened at the end of October 2004," says the Coop Forum manager.

    One figure Coop management did release, and that's how much the 7,000 items were reduced on average: five percent.

  • The Old New Thing

    Pointers to virtual functions with adjustors

    • 8 Comments

    As a mental exercise, let's combine two mind-numbing facts about pointers to member functions, namely that all pointers to virtual functions look the same and that pointers to member functions are very strange animals. The result may make your head explode.

    Consider:

    class Class1 {
     public: virtual int f() { return 1; }
    };
    
    class Class2 {
     public: virtual int g() { return 2; }
    };
    
    class Class3 : public Class1, public Class2 {
    };
    
    int (Class3::*pfn)() = Class3::g;
    

    Here, the variable pfn consists of a code pointer and an adjustor. The code pointer gives you the virtual call stub:

     mov eax, [ecx]             ; first vtable
     jmp dword ptr [eax]        ; first function
    

    and the adjustor is sizeof(Class1) (which in our case would be 4 on a 32-bit machine). The result, then, of compiling a function call (p->*pfn)() might look something like this:

     mov ecx, p
     lea eax, pfn
     add ecx, dword ptr [eax+4] ; adjust
     call dword ptr [eax]       ; call
    -- transfers to
     mov eax, [ecx]             ; first vtable
     jmp dword ptr [eax]        ; first function
    -- transfers to
     mov eax, 2                 ; return 2
     ret
    

    Okay, I lied. It's really not all that complicated after all. But you can probably still impress your friends with this knowledge. (If you have really geeky friends.)

  • The Old New Thing

    Why does the debugger show me the wrong virtual function?

    • 22 Comments

    Pointers to virtual functions all look basically the same and therefore, as we learned last time, all end up merged into a single function. Here's a contrived example:

    class Class1
    {
    public:
     virtual int f1() { return 0; }
     virtual int f2() { return 1; }
    };
    
    class Class2
    {
    public:
     virtual int g1() { return 2; }
     virtual int g2() { return 3; }
    };
    
    int (Class1::*pfn1)() = Class1::f2;
    int (Class2::*pfn2)() = Class2::g2;
    

    If you take a look at pfn1 and pfn2 you'll see that the point to the same function:

    0:000> dd pfn1 l1
    01002000  010010c8
    0:000> dd pfn2 l1
    01002004  010010c8
    0:000> u 10010c8 l2
    010010c8 8b01     mov     eax,[ecx]           ; first vtable
    010010ca ff6004   jmp     dword ptr [eax+0x4] ; second function
    

    That's because the virtual functions Class1::f2 and Class2::g2 are both stored in the same location relative to the respective object pointer: They are the second entry in the first vtable. Therefore, the code to call those functions is identical and consequently has been merged by the linker.

    Notice that the function pointers are not direct pointers to the concrete implementations of Class1::f2 and Class2::g2 because the function pointer might be applied to a derived class which override the virtual function:

    class Class3 : public Class1
    {
    public:
     virtual int f2() { return 9; }
    };
    
    Class3 c3;
    (c3.*pfn1)(); // calls Class3::f2
    

    Applying the function pointer invokes the function on the derived class, which is the whole point of declaring the function Class1::f2 as virtual in the first place.

    Note that the C++ language explicitly states that the result of comparing non-null pointers to virtual member functions is "unspecified", which is language-standards speak for "the result not only depends on the implementation, but the implementation isn't even required to document how it arrives at the result."

  • The Old New Thing

    Why does the debugger show me the wrong function?

    • 44 Comments

    Often you'll be minding your own business debugging some code, and you decide to step into one function and the debugger shows that you're in some other function. How did that happen?

    class Class1
    {
    public:
     int *GetQ() { return q; }
    private:
     int *p;
     int *q;
    };
    
    class Class2
    {
    public:
     virtual int GetValue() { return value; }
    private:
     int value;
    };
    

    You then step through code that does something like this:

    int Whatever(Class2 *p)
    {
     return p->GetValue();
    }
    

    And when you step into the call to p->GetValue() you find yourself in Class1::GetQ. What happened?

    What happened is that the Microsoft linker combined functions that are identical at the code generation level.

    ?GetQ@Class1@@QAEPAHXZ PROC NEAR    ; Class1::GetQ, COMDAT
      00000 8b 41 04         mov     eax, DWORD PTR [ecx+4]
      00003 c3               ret     0
    ?GetQ@Class1@@QAEPAHXZ ENDP         ; Class1::GetQ
    
    ?GetValue@Class2@@UAEHXZ PROC NEAR  ; Class2::GetValue, COMDAT
      00000 8b 41 04         mov     eax, DWORD PTR [ecx+4]
      00003 c3               ret     0
    ?GetValue@Class2@@UAEHXZ ENDP       ; Class2::GetValue
    

    Observe that at the object code level, the two functions are identical. (Note that whether two functions are identical at the object code level is highly dependent on which version of what compiler you're using, and with which optimization flags. Identical code generation for different functions occurs with very high frequency when you use templates.) Therefore, the linker says, "Well, what's the point of having two identical functions? I'll just keep one copy and use it to stand for both Class1::GetQ and Class2::GetValue."

    0:000> u Class1::GetQ
    010010d6 8b4104           mov     eax,[ecx+0x4]
    010010d9 c3               ret
    0:000> u Class2::GetValue
    010010d6 8b4104           mov     eax,[ecx+0x4]
    010010d9 c3               ret
    

    Notice that the two functions were merged: The addresses are identical. That one fragment of code merely goes by two names. Therefore, when the debugger sees that you've jumped to 0x010010d6, it doesn't know which of the names it should use, so it just picks on.

    That's why it looks like you jumped to the wrong function.

    To disable what is called "identical COMDAT folding", you can pass the /OPT:NOICF flag to the linker.

  • The Old New Thing

    Psychic debugging: Why your expensive four-processor machine is ignoring three of its processors

    • 57 Comments

    On one of our internal mailing lists, someone was wondering why their expensive four-processor computer appeared to be using only one of its processors. From Task Manager's performance tab, the chart showed that the first processor was doing all the work and the other three processors were sitting idle. Using Task Manager to set each process's processor affinity to use all four processors made the computer run much faster, of course. What happened that messed up all the processor affinities?

    At this point, I invoked my psychic powers. Perhaps you can too.

    First hint: My psychic powers successfully predicted that Explorer also had its processor affinity set to use only the first processor.

    Second hint: Processor affinity is inherited by child processes.

    Here was my psychic prediction:

    My psychic powers tell me that

    1. Explorer has had its thread affinity set to 1 proc....
    2. because you previewed an MPG file...
    3. whose decoder calls SetProcessAffinityMask in its DLL_PROCESS_ATTACH...
    4. because the author of the decoder couldn't fix his multiproc bugs...
    5. and therefore set the process thread affinity to 1 to "fix" the bugs.

    Although my first psychic prediction was correct, the others were wide of the mark, though they were on the right track and successfully guided further investigation to uncover the culprit.

    The real problem was that there was a third party shell extension whose authors presumably weren't able to fix their multi-processor bugs, so they decided to mask them by calling the SetProcessAffinityMask function to lock the current process (Explorer) to a single processor. Woo-hoo, we fixed all our multi-processor bugs at one fell swoop! Let's all go out and celebrate!

    Since processor affinity is inherited, this caused every program launched by Explorer to use only one of the four available processors.

    (Yes, the vendor of the offending shell extension has been contacted, and they claim that the problem has been fixed in more recent versions of the software.)

  • The Old New Thing

    Confusion over whether you have Windows XP SP1 or SP2

    • 38 Comments

    Some support people have asked me why the "About" dialog seems to be kind of schizophrenic as to whether a machine has Windows XP SP1 or SP2.

    About Windows

    Microsoft® Windows
    Version 5.1 (Build 2600.xpsp2.040919-1003 : Service Pack 1)
    Copyright© 1981-2001 Microsoft Corporation

    Why does the version string say "xpsp2" and then "Service Pack 1"? Is this machine running SP1 or SP2?

    It's running Service Pack 1. The build number string is a red herring.

    Why does the build number string say "xpsp2" when the computer is running SP1?

    Because Windows XP Service Pack 2 was a victim of changing circumstances.

    After Service Pack 1 shipped, there was no indication that Service Pack 2 was going to be anything other than "just another service pack": A cumulative update of the fixes that had been issued since the release of Service Pack 1. Therefore, the release team created a new project, called it "xpsp2" and when a fix needed to be made to Service Pack 1, they made it there. It was called "xpsp2" because the assumption was that when the time came to release Service Pack 2, they would just take all the fixes they had been making to Service Pack 1 and call that Service Pack 2. In other words, "fixes to Service Pack 1" and "working on Service Pack 2" were the same thing.

    Of course, things changed, and a "new" Service Pack 2 project was created for the "real" Service Pack 2 changes, leaving the old "xpsp2" project to be merely the place where Service Pack 1 fixes were developed.

    Yes, it's confusing. We're kind of embarrassed by the whole project naming fiasco. That's what happens when plans take a radical change after work has already started.

    Anyway, there you have it, the long and boring story of why fixes for Service Pack 1 have "xpsp2" in their build string.

  • The Old New Thing

    Your exception handler can encounter an exception

    • 26 Comments

    Consider the following code, written in C# just for kicks; the problem is generic to any environment that supports exception handling.

    void ObliterateDocument()
    {
     try {
      try {
       document.DestroyAll();
      } finally {
       document.Close();
       document.DestroyExtensions();
       document.DestroyPlugins();
      }
     } finally {
      document.Destroy();
     }
    }
    

    Some time later, you find yourself facing an assertion failure from document.Destroy() claiming that you are destroying the document while there are still active plugins. But there is your call to document.DestroyPlugins(), and it's in a finally block, and the whole point of a finally block is that there is no way you can escape without executing it.

    So why didn't document.DestroyPlugins() execute?

    Because your exception handler itself encountered an exception.

    The exception handler is not active during its own finally clause. As a result, if an exception is thrown during document.Close(), the exception handler search begins at the block outside the finally block.

    (That the exception handler is not active during its own finally clause should be obvious. It would mean that if an exception were to occur during the finally clause, the program would go into an infinite loop. And it also wouldn't be possible to rethrow a caught exception; your throw would end up caught by yourself!)

    In this case, the exception was caught by some outer caller, causing the remainder of the first finally block to be abandoned. The other finally blocks do run since they contain the one that died.

    (This bug also exists in the proposed alternative to error-checking code posted by an anonymous commenter.)

  • The Old New Thing

    Competing to be the worst-dressed couple in America

    • 24 Comments

    The U.S. cable network TLC is putting on a special episode of What Not to Wear devoted to identifying the worst-dressed couple in America. It so happens that one of my friends knows one of the finalists, so we'll be rooting for them. Or is it against them? Are you supposed to hope that your favorite is in fact the worst-dressed? Or should you be relieved that they're only "sort of badly dressed but at least not the worst I've seen"?

    Yes, the show is a rip-off of the original BBC show. It's interesting how we yanks look to our British neighbors as examples of quality television (What Not to Wear, Changing Rooms, The Office) and bemoan how U.S. television producers can only come up with drivel. Meanwhile, the Brits look right back (Hill Street Blues, Cheers, 24) and bemoan the same thing about their own television industry.

    The other guy's stuff is always better.

  • The Old New Thing

    The great Alaskan ice sculpture

    • 3 Comments

    NPR interviewed John Reeves, the artist behind a 160-foot-tall mountain of ice in Alaska. The man has a down-home aw-shucks kind of demeanor that I found quite charming.

    I'm a middle-aged guy that has a lot of time in the winter and a little bit of extra money to play with, so my hobby was to see how big an ice hill I could grow. I started last year as just a way to amuse myself just to see what would happen if you left the water running all winter, and last year's model was so interesting and so much fun that this year I decided to continue doing it.

    Well, a long winter in Alaska will do that to you, I guess.

    Yes it will. A long, cold, dark... lengthy, cold... did I mention cold?

  • The Old New Thing

    Windows NT Security in Theory and Practice

    • 4 Comments

    Today, I'm not writing anything new. Instead, I'm referring you to the series of articles by Ruediger Asche starting with Windows NT Security in Theory and Practice. These articles are quite old but the principles are still sound. Just bear in mind that the newer stuff won't be covered.

Page 362 of 431 (4,306 items) «360361362363364»