January, 2010

  • The Old New Thing

    People just like you, for certain values of you

    • 39 Comments

    I received a brochure in the mail for a local church which says that it's "full of people just like you."

    Everybody in the brochure is white.

    "You'll fit right in!" it concludes.

    Bonus chatter: My friends guessed that perhaps the church members are all computer programmers who work at Microsoft and speak Swedish badly.

  • The Old New Thing

    It's fine to rename a function in your DEF file, but when you do, you have to link to that function by its new name

    • 18 Comments

    Jeffrey Riaboy asks why, if he renames a function in his DEF file, attempts to link to the function by its old name fail.

    Well, um, yeah, because you renamed it.

    Let's take the situation apart a bit; maybe it'll make more sense. I'm going to ignore a lot of details (dllimport/dllexport, calling conventions) since they are not relevant to the discussion and would end up just being distracting. I'm also going to assume we are running on an x86-class machine, just for concreteness. The same discussion works for other platforms; you just have to adjust the conventions accordingly.

    First, here is some source code for a DLL, let's call it FRED.DLL:

    int Dabba()
    {
      return 0;
    }
    
    int Doo()
    {
      return 1;
    }
    

    And here is the DEF file for FRED.DLL:

    EXPORTS
     Yabba=Dabba
     Dabba=Doo
    

    When you compile this DLL, the result will be something like this:

    FRED.DLL:
     Yabba -> return 0;
     Dabba -> return 1;
    

    The function exported as Yabba returns 0 because the DEF file said, "I want to export a function with the exported name Yabba; when somebody calls the function, I want control to go to the function I called Dabba internally."

    Similarly, the function exported as Dabba returns 1 because the DEF file said, "I want to export a function with the exported name Dabba; when somebody calls the function, I want control to go to the function I called Doo internally."

    Remember that symbolic information disappears during linking. The names of the functions and variables in the original source code are not stored anywhere in the DLL. The names exist only so that the linker can resolve symbolic references between object files. Once that's done, the names are discarded: Their work is done. (See The classical model for linking for a discussion of how linking works under the classical model.)

    Exported functions are also a mapping between labels and functions, but this mapping is not used when linking the DLL; rather, it is just a table the linker produces under the direction of your DEF file. To reduce confusion for the programmer writing the DLL, the name in the exported function table usually matches the name in the object files, but that is merely a convention. An entry in the export table that doesn't perform renaming is just a shorthand for "I would like the exported name for this function to be the same as its internal name." It's a convenient typing-saver.

    By analogy, Microsoft employees have one email address for use inside the company, and a different email address for use outside the company. Some employees choose to have their external email address be the same as their internal one, but that is hardly a requirement.

    Meanwhile, the import library for our DLL looks something like this:

    FRED.LIB:
     __imp__Yabba -> FRED.Yabba
     __imp__Dabba -> FRED.Dabba
    
     _Yabba@0 -> jmp [__imp__Yabba]
     _Dabba@0 -> jmp [__imp__Dabba]
    

    As we saw before, each exported function results in two symbols in the import library, one with __imp_ prepended to the exported name, which represents the import table entry, and one containing a stub function for the benefit of a naïve compiler.

    Now let's look at a program that wants to call some functions from FRED.DLL:

    int Flintstone()
    {
     Yabba();
     Dabba();
     Doo();
    }
    

    Let's say that these functions were not declared as dllimport, just for the sake of concreteness. (The discussion works the same if they were declared as dllimport, making the appropriate changes to the symbol names.) When the linker goes to resolve the call to Yabba@0, it will find the entry in FRED.DLL that says, "I've got a function called Yabba@0; the code for it is the single instruction jmp [__imp__Yabba]." When the program calls this function, the jmp instruction will jump through the import table entry for FRED.Yabba, which will wind up at the function in FRED.DLL exported under the name Yabba. If we look inside FRED.DLL, we see that this is a function that returns 0 (because it is the function which was called Dabba in the original source code, although that information was lost a long time ago).

    Similarly, when the linker resolves the call to Dabba@0, it finds the entry in FRED.DLL which pulls in the one-line stub function which jumps through the import table entry for Dabba@0. This leads to a function that returns 1, a function which was called Doo in the original source code.

    However, that last call to Doo raises a linker error because it cannot find a function called Doo in the FRED.LIB import library. That's just the internal name for a function in the source code for FRED.DLL, a name which was lost during linking. If you want to call the function which had been called Doo in the original source code, you have to import it by its new name, Dabba.

    In Jeffrey's case, he took a function which was internally referred to by a decorated name (?Dispose@MyClass@@QAEAAV1@XZ) and renaming it to an undecorated name (MC_Dispose). But when other modules tried to use the library, they got the error saying that "?Dispose@MyClass@@QAEAAV1@XZ" is not found. Which is correct: ?Dispose@MyClass@@QAEAAV1@XZ was not found because it no longer exists under that name. You renamed it to MC_Dispose. Those modules need to link to the function MC_Dispose if they want to call the function "formerly known as ?Dispose@MyClass@@QAEAAV1@XZ".

    Actually, Jeffrey's situation is more complicated than I described it because ?Dispose@MyClass@@QAEAAV1@XZ undecorates to public: class MyClass & __thiscall MyClass::Dispose(void); this is a method not a static function. I don't believe there's a way to override the name decoration algorithm for instance methods; the compiler is always going to generate a reference to ?Dispose@MyClass@@QAEAAV1@XZ. So renaming the export doesn't buy you anything because you don't control the name on the import side.

  • The Old New Thing

    How you might be loading a DLL during DLL_PROCESS_DETACH without even realizing it

    • 12 Comments

    As you are I'm sure aware, you shouldn't be doing much of anything in your DllMain function, but you have to watch out for cases where you end up doing them accidentally.

    Some time ago, I was investigating a failure which was traced back to loading a DLL inside DLL_PROCESS_DETACH. Wait, what kind of insane person loads a DLL as part of shutting down? Shouldn't you be cleaning up stuff, not creating new stuff?

    The following is not the actual code, but it captures the same spirit:

    INFO *CachedInfo;
    
    BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, void *pvReserved)
    {
      switch (dwReason) {
      ...
      case DLL_PROCESS_DETACH:
        ...
        CoTaskMemFree(CachedInfo);
        ...
      }
      return TRUE;
    }
    

    There is some global variable that contains a pointer to memory that was allocated by CoTaskMemAlloc. In this case, I made it a cache, but the details aren't important. When the DLL is detached from the process, we free the cached memory so we don't have a leak. Since it is okay to pass NULL to the CoTaskMemFree function (it simply returns without doing anything), the cleanup code works even if we never called a function that put a value into the cache.

    Except that this code ended up loading a DLL. The reason is delay-loading.

    The authors of this DLL sped up its load time by marking OLEAUT32.DLL as a delay-loaded DLL, which means that it doesn't get loaded until somebody calls a function in it.

    And in fact, nobody called a function from OLEAUT32. Ever.

    "Hooray!" you shout. "We avoided loading OLEAUT32 altogether." After all, the fastest code is code that doesn't run.

    Except that it does run. Right there. In your DLL_PROCESS_DETACH handler.

    Since nobody called a function from OLEAUT32, the call to CoTaskMemFree was the first call to OLEAUT32 and therefore caused it to be loaded. From inside a DLL_PROCESS_DETACH handler.

    Delay-loading is one of those features that is very convenient and saves you a lot of typing (namely, writing those stub functions yourself), but you also have to understand what's going on so you don't use it incorrectly. (In this case, a superficially-redundant if (CachedInfo != NULL) test needs to be inserted.)

  • The Old New Thing

    I could just use a picture of a regular-sized shopping cart from farther away

    • 6 Comments

    Internet retailer woot! went to CES 2010 and covered it on their blog. (CES category.) But they don't cover what the media elite cover, the big announcements, the hot products. Nope, they cover the weird stuff.

    They have uncrating photos of CES itself, they infiltrate the The Consumer Breakfast Buffet Show, and they take super secret spy pictures of a miniature shopping cart.

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: If they can inject code, then they can run code

    • 20 Comments

    One category of the dubious security vulnerability is designing an insecure system, putting together an exploit, and then blaming one of the components of the exploit rather than the insecure system in the first place.

    I have found a critical security vulnerability in the XYZ scripting object which permits modifying files on the Web server itself.

    To effect this exploit, write a script which instantiates the control and use the Save method to tell it to save its contents. The Save method does not attempt to block directory traversal, so you can pass any path to the Save method and overwrite any file on the server.

    To deploy this exploit, find a Web server which has a writeable directory that also has execute permission and which executes scripts as SYSTEM. Upload the script to the server, and then from another machine, visit the Web server to view the page you just uploaded. The Web server will execute the script as a server-side script, and the target file will be overwritten.

    Well, yes, this whole set-up is definitely vulnerable, but why are you blaming the XYZ scripting object? For one thing, you can do exactly the same thing with any other scripting object that can write files. For example, just use the FileSystemObject object. In fact, that object is even better than the XYZ object, because the file system object lets you control what is written!

    But the real security vulnerability is that the person who set up the Web site did so insecurely. If you let untrusted users upload scripts to the server and configure the server to execute them as SYSTEM without restriction, then naturally those users can upload scripts that do dangerous things to the server. That's not the script's fault; it's the fault of the person who set up the Web server to execute those scripts in such an insecure manner in the first place! (You might have a case if the insecure configuration is the default, but I don't know of any modern servers that do.)

  • The Old New Thing

    News flash: Wearing clothing keeps you warm

    • 12 Comments

    Every so often, I'll run across a statement of the obvious disguised as news and post it to the News flash tag, but the ones I've found have nothing on this collection of the 11 Most Painfully Obvious Newspaper Articles Ever. Just click through and slap your forehead.

    Bonus News Flash: Mark McGwire used steroids. I can't wait to see what other breaking news stories we'll have in the coming days. "Pope's religion identified." "Bear feces found in forest."

  • The Old New Thing

    Why does GetCommandLine give me a corrupted command line?

    • 10 Comments

    A customer had the following problem:

    We're calling GetCommandLine to retrieve the command line, and the documentation says that it returns a single null-terminated string. However, when we call it in our application, we find that it is actually a double-null-terminated string. The buffer returned consists of a series of null-terminated strings, one string per word on the command line, all stored one after the other, and with two null terminators at the end. How do I get the original string?

    Recall that the command line is just a conveniently-initialized variable in a process and once it's set up, the kernel doesn't really care about it any more.

    What is most likely happening is that somebody is taking the raw command line returned by GetCommandLine and writing to it. The customer can confirm this by dumping the command line just as the process starts, even before any DLLs get to run their DllMains, and then setting a write breakpoint on the command line to see who is writing to it.

    And in fact, the customer did find the culprit.

    It turns out it was some other part of the code (not written by me!) which was parsing the command line and writing into it in the process.
  • The Old New Thing

    But that's not all: The story of that cheesy Steve Ballmer Windows video

    • 15 Comments

    While it's true that the cheesy Steve Ballmer Windows video had bad music, bad hair, and bad acting, it's also true that all that cheese was intentional.

    That video was produced for and shown at the Company Meeting, back when a mainstay of the Company Meeting was spoofs of popular television advertisements—what today would be called "virally popular"—with Bill Gates and other senior executives taking the starring roles. The "Crazy Steve" video was a spoof of late-night television advertisements, the most direct influence being the popular-at-the-time Crazy Eddie commercials.

    So enjoy the "Crazy Steve" video, but don't fool yourself into thinking this was a real commercial.

    Bonus commercial chatter: I don't know the story behind the commercial produced by crack-smoking monkeys. It was shot in one of the Microsoft old-campus buildings, but I don't recognize any of the actors. This leaves open the horrific possibility that the advertisement was for real!

    Extra bonus chatter: The original Windows XP commercial, featuring Madonna's Ray of Light, had to be abandoned less than two months before launch thanks to the events of September 11, 2001: A commercial featuring people flying was deemed to be in bad taste so soon after the event. I don't know how they did it, but the marketing department managed to put together a new ad campaign in less than two months. (This also explains why some online ads for Windows XP employed the song Ray of Light, even though the song had nothing to do with the new Windows XP ad campaign: They were leftovers which could be salvaged because they didn't depict flying.)

    Too bad, because I liked the original campaign.

    Double secret bonus chatter: Could this be proto-Kylie?

    Update: an article which includes another story about the filming of the spoof commercial.

  • The Old New Thing

    Weight Gain 4000, the competition

    • 9 Comments

    Some years ago, one of my colleagues mentioned at the lunch table, "I went hiking this weekend, and man, my backpack was so heavy. I weighed it, and it was like 35 pounds. And then I realized, wait a second, I'm overweight by 35 pounds. I'm carrying this heavy backpack all the time!"

    Thus began a collective weight loss competition we called Weight Gain 4000, named after an episode of South Park which had aired recently. ("I'm not fat; I'm big-boned!") I set up a Web page where people could enter their current weight, and it charted everyone's pounds over target weight as a function of time. Oh, and the goal was to lose weight, not gain it.

    It so happened that I won this little competition with the aid of some extra bike rides. Then again, I also had the least amount of weight to lose. And my colleagues accused me of cheating because I managed to accelerate my weight loss as the deadline approached. (But I didn't cheat, honest!)

    I was reminded of this competition from years ago when I read about John Dirks and Adam Orkand who also learned that an effective way to make you stick to your weight loss plan is to make a wager out of it.

  • The Old New Thing

    Pros and cons of using a four-year-old as your language instructor

    • 15 Comments

    I have a niece who is a native speaker of Chinese. Playing with her is a free language lesson, and there are advantages and disadvantages.

    One advantage is that you will learn all the basic words, and you won't run the risk that your instructor will accidentally use some advanced vocabulary that will throw you off. (You also learn some words that are very important to young children like butt and fart.)

    Fortunately, my niece's pronunciation is very good, so it's not like I'm accidentally learning to speak with a lisp or a childhood speech impediment.

    One disadvantage is that you're learning kiddie-talk: My niece uses the word for doggie rather than dog, for example.

    A bigger problem is that you might learn the words wrong. While playing with some animal dolls, my niece (four years old at the time) taught me the word 頭骨. I didn't know what it meant, but I repeated it to her satisfaction. During a break in play, I asked her aunt, "Hey, I just learned the word 頭骨. What does it mean?"

    Her aunt didn't know either. She went back to my niece for clarification. "What did you just teach Uncle Raymond?"

    After some discussion, her aunt figured it out. My niece got the word wrong. It's not 頭骨; it's 骨頭. (It means bone.)

    Apparently this mistake of flipping the syllables of a word is not exclusive to Chinese. Her aunt asked her, "What do you want to eat?"

    — Apple pie! was her reply in English.

    "There's no apple pie here."

    — It's right there!

    "That's not apple pie. It's pineapple."

    My niece patiently explained, "Grown-ups say pineapple, but kids say apple pie."

    Bonus chatter: The nieces are encouraged to speak with me in Chinese rather than English. They take this as an opportunity to tease me by asking questions they think I can't answer by using words I don't know. Last night, one of them asked me, "When we get to your house, can I hit your butt?" She thought she was being so sneaky; apparently she forgot that she's the one who taught me the word butt.

Page 2 of 4 (32 items) 1234