• The Old New Thing

    Link-time code generation invalidates a lot of classical assumptions about linking

    • 31 Comments

    The discussion of DLL imports and exports from a few years back relied heavily on what I called the classical model of linking. Even though modern linkers can be quite non-classical, they do what they can to preserve certain aspects of classical behavior because many projects still rely on them.

    Recall that the classical division of labor between the compiler and the linker is that the compiler takes source code and generates machine code with a few blank spaces that says, "Hey, linker, I'm not sure what number goes here, but I want it to be the address of X. Please patch the correct number in when you figure it out where X is." The linker's job is to go find X, assign it an address, and patch the address of X into all the places that the compiler asked for.

    In the Visual Studio system, one of the ways of activating a large set of non-classical behaviors is to enable Whole program optimization, also known as Link-time code generation. When this is enabled, the division of labor between the compiler and linker shifts. The compiler still takes source code, but instead of generating machine code, it merely generates a parse tree (perhaps partially-digested). The linker then takes all these parse trees, combines them together (according to classical rules), and generates machine code.

    Since the code generation is done with the full parse tree of the entire program, the code generator can perform very advanced operations, like observing that a method is never overridden and can therefore be inlined. In particular, starting with Visual Studio 2012, the link-time code generator can even see that you got dllimport wrong, and it goes back in time and redeclares the function correctly before proceeding with code generation.

    Non-classical linking is even more advanced than non-classical physics. Whereas special relativity lets you stretch and slow down time, non-classical linking even gives you a limited form of time travel.

  • The Old New Thing

    Closing over the loop variable is just as harmful in JavaScript as it is in C#, and more cumbersome to fix

    • 38 Comments

    Prerequisite reading: Closing over the loop variable considered harmful.

    JavaScript has the same problem. Consider:

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      document.getElementById("myButton" + i)
       .addEventListener("click",
             function() { alert(i); });
     }
    }
    

    The most common case where you encounter this is when you are hooking up event handlers in a loop, so that's the case I used as an example.

    No matter which button you click, they all alert 4, rather than the respective button number.

    The reason for this is given in the prerequisite reading: You closed over the loop variable, so by the time the function actually executed, the variable i had the value 4, since that's the leftover value after the loop is complete.

    The cumbersome part is fixing the problem. In C#, you can just copy the value to a scoped local and capture the local, but that doesn't work in JavaScript:

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      var j = i;
      document.getElementById("myButton" + i)
       .addEventListener("click",
             function() { alert(j); });
     }
    }
    

    Now the buttons all alert 3 instead of 4. The reason is that JavaScript variables have function scope, not block scope. Even though you declared var j inside a block, the variable's scope is still the entire function. In other words, it's as if you had written

    function hookupevents() {
     var j;
     for (var i = 0; i < 4; i++) {
      j = i;
      document.getElementById("myButton" + i)
       .addEventListener("click",
             function() { alert(j); });
     }
    }
    

    Here's a function which emphasizes this "variable declaration hoisting" behavior:

    function strange() {
     k = 42;
     for (i = 0; i < 4; i++) {
      var k;
      alert(k);
     }
    }
    

    The function alerts 42 four times because the variable k refers to the same variable k throughout the entire function, even before it has been declared.

    That's right. JavaScript lets you use a variable before declaring it.

    The scope of JavaScript variables is the function, so if you want to create a variable in a new scope, you have to put it in a new function, since functions define scope.

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      var handlerCreator = function(index) {
       var localIndex = index;
       return function() { alert(localIndex); };
      };
      var handler = handlerCreator(i);
      document.getElementById("myButton" + i)
       .addEventListener("click", handler);
     }
    }
    

    Okay, now things get weird. We need to put the variable into its own function, so we do that by declaring a helper function handler­Creator which creates event handlers. Since we now have a function, we can create a new local variable which is distinct from the variables in the parent function. We'll call that local variable local­Index. The handler creator function saves its parameter in the local­Index and then creates and returns the actual handler function, which uses local­Index rather than i so that it uses the captured value rather than the original variable.

    Now that each handler gets a separate copy of local­Index, you can see that each one alerts the expected value.

    Now, I wrote out the above code the long way for expository purposes. In real life, it's shrunk down quite a bit.

    For example, the index parameter itself can be used instead of the local­Index variable, since parameters can be viewed as merely conveniently-initialized local variables.

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      var handlerCreator = function(index) {
       return function() { alert(index); };
      };
      var handler = handlerCreator(i);
      document.getElementById("myButton" + i)
       .addEventListener("click", handler);
     }
    }
    

    And then the handler­Creator variable can be inlined:

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      var handler = (function(index) {
       return function() { alert(index); })(i);
      document.getElementById("myButton" + i)
       .addEventListener("click", handler);
     }
    }
    

    And then the handler itself can be inlined:

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      document.getElementById("myButton" + i)
       .addEventListener("click",
           (function(index) {
             return function() { alert(index); })(i));
     }
    }
    

    The pattern (function (x) { ... })(y) is misleadingly called the self-invoking function. It's misleading because the function doesn't invoke itself; the outer code is invoking the function. A better name for it would be the immediately-invoked function since the function is invoked immediately upon definition.

    The next step is to change then the name of the helper index variable to simply i so that the connection between the outer variable and the inner variable can be made more obvious (and more confusing to the uninitiated):

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      document.getElementById("myButton" + i)
       .addEventListener("click",
           (function(i) {
             return function() { alert(i); })(i));
     }
    }
    

    The pattern (function (x) { ... })(x) is an idiom that means "For the enclosed block of code, capture x by value." And since functions can have more than one parameter, you can extend the pattern to (function (x, y, z) { ... })(x, y, z) to capture multiple variables by value.

    It is common to move the entire loop body into the pattern, since you usually refer to the loop variable multiple times, so you may as well capture it just once and reuse the captured value.

    function hookupevents() {
     for (var i = 0; i < 4; i++) {
      (function(i) {
       document.getElementById("myButton" + i)
        .addEventListener("click", function() { alert(i); });
      })(i);
     }
    }
    

    Maybe it's a good thing that the fix is more cumbersome in JavaScript. The fix for C# is easier to type, but it is also rather subtle. The JavaScript version is quite explicit.

    Exercise: The pattern doesn't work!

    var o = { a: 1, b: 2 };
    document.getElementById("myButton")
     .addEventListener("click",
       (function(o) { alert(o.a); })(o));
    o.a = 42;
    

    This code alerts 42 instead of 1, even though I captured o by value. Explain.

    Bonus reading: C# and ECMAScript approach solving this problem in two different ways. In C# 5, the loop variable of a foreach loop is now considered scoped to the loop. ECMAScript code name Harmony proposes a new let keyword.

  • The Old New Thing

    Why did it take so long for Windows to support a taskbar on more than one monitor?

    • 83 Comments

    Mark wants to know why Windows has never supported having a taskbar on more than one monitor. (The question was asked before Windows 8 multi-monitor taskbar support became publically-known.)

    The feature has always been on the list, but it's a long list, and specifically the cost of designing, implementing, testing, performing usability tests, then redesigning the feature (because you will definitely need to redesign something as significant as this at least once) historically prevented it from escaping the minus-100-point deficit.

    Features do not exist in a vacuum, and decisions about features necessarily take into account the other features under consideration. For a feature to be adopted, it not only must be valuable enough in itself, but it almost must provide a better cost/benefit ratio than any other features under consideration. While the benefit of a multi-monitor taskbar is high, you have to scale it down by the percentage of users who would be able to take advantage of such a feature. I don't know the exact numbers, but I would hazard that fewer than ten percent of users use a multiple-monitor system on a regular basis, so any benefit would have to be ten times as great as the benefit of features that have broader use.

    On top of that, the development cost of a multiple-monitor taskbar is significantly higher than most other taskbar features. Just the compatibility constraints alone make you shudder. (Think about all the programs that do a Find­Window looking for the taskbar and assuming that there is only one.)

    What changed in Windows 8 that made a multiple-monitor taskbar a feature worth implementing? I don't know, but I can guess. First of all, the overall engineering budget for the taskbar may have been raised, so that more features from the list can make the cut. Or maybe the people in charge of the taskbar decided to go with their gut and ignore the numbers, implementing a feature specifically targetting the enthusiast community even though the work would not be justified if you went strictly by the cost/benefit analysis. By doing this, they ended up short-changing other features which were perhaps more worthy if you looked at the numbers.

    And then you'd be asking, "Why didn't you do feature Y? I mean, it would have been far more useful to far more people than the multiple-monitor taskbar."

    (Of course, now that I mentioned Windows 8, everybody will treat this as open season to post their complaints here.)

  • The Old New Thing

    As long as your file names meet operating system requirements, you can use whatever you like; the rest is up to you

    • 64 Comments

    A customer had a question about the MSDN documentation on rules for legal file names:

    My employees keep naming documents with hyphens in the name. For example, they might name a file Budget-2012-Final.xlsx. It is my position that hyphens should not be used in this way, and the document should be named Budget 2012 Final.xlsx. Please advise on the use of hyphens within file names.

    Hyphens inside file names are legal, and you can use as many as you like, subject to the other rules for file names.

    If you are having an argument with your employees about file naming conventions, that's something you just need to work out among yourselves. Whatever you decide, the file system will be there for you.

  • The Old New Thing

    Obtaining information about the user's wallpaper on multiple monitors

    • 11 Comments

    Today we're going to dump information about the user's wallpaper settings on multiple monitors.

    The idea is simple. You use the IDesktop­Wallpaper interface on the Desktop­Wallpaper object to get information about the desktop wallpaper. It will tell you the wallpaper positioning information, whether a single image is being used for all monitors, where those monitors are, and which image is on which monitor.

    #define UNICODE
    #define _UNICODE
    #define STRICT
    #include <windows.h>
    #include <shlobj.h>
    #include <atlbase.h>
    #include <atlalloc.h>
    #include <stdio.h> // horrors! mixing C and C++!
    
    int __cdecl wmain(int, wchar_t **)
    {
     CCoInitialize init;
    
     // Create the DesktopWallpaper object
     CComPtr<IDesktopWallpaper> spdw;
     CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_ALL,
                      IID_PPV_ARGS(&spdw));
    
     // See if there is a single wallpaper on all monitors.
     CComHeapPtr<wchar_t> spszCommonWallpaper;
     HRESULT hr = spdw->GetWallpaper(nullptr, &spszCommonWallpaper);
     switch (hr) {
     case S_OK:
      printf("Same wallpaper on all monitors: %ls\n",
             static_cast<wchar_t *>(spszCommonWallpaper));
      break;
     case S_FALSE:
      printf("Different wallpaper on each monitor\n");
      break;
     default:
      printf("Mysterious error: 0x%08x\n", hr);
      break;
     }
    
     // Get the number of monitors,
     UINT count;
     spdw->GetMonitorDevicePathCount(&count);
     printf("There are %d monitors\n", count);
    
     // Print information about each monitor.
     for (UINT i = 0; i < count; i++) {
      // Get the device path for the monitor.
      CComHeapPtr<wchar_t> spszId;
      spdw->GetMonitorDevicePathAt(i, &spszId);
      printf("path[%d] = %ls\n",
             i, static_cast<wchar_t *>(spszId));
    
      // Get the monitor location.
      RECT rc;
      spdw->GetMonitorRECT(spszId, &rc);
      printf("rect = (%d, %d, %d, %d)\n",
             rc.left, rc.top, rc.bottom, rc.right);
    
      // Get the wallpaper on that monitor.
      CComHeapPtr<wchar_t> spszWallpaper;
      hr = spdw->GetWallpaper(spszId, &spszWallpaper);
      printf("image = %ls\n",
             static_cast<wchar_t *>(spszWallpaper));
     }
    
     return 0;
    }
    

    The program proceeds in a few basic steps.

    We create the Desktop­Wallpaper object. That object will give us the answers to our questions.

    Our first question is, "Is the same wallpaper being shown on all monitors?" To determine that, we call IDesktop­Wallpaper::Get­Wallpaper and specify nullptr as the monitor ID. The call succeeds with S_OK if the same wallpaper is shown on all monitors (in which case the shared wallpaper is returned). It succeeds with S_FALSE if each monitor has a different wallpaper.

    To get information about the wallpaper on each monitor, we iterate through them, first asking for the monitor device path, since that is how the Desktop­Wallpaper object identifies monitors. For each monitor, we ask for its location and the wallpaper for that monitor. Note that if the monitor is not displaying a wallpaper at all, the Get­Wallpaper method succeeds but returns an empty string.

    And that's it. You can juice up this program by asking for wallpaper positioning information, and if you are feeling really adventuresome, you can use the Set­Wallpaper method to change the wallpaper.

  • The Old New Thing

    Why does GetFileVersionInfo map the whole image into memory instead of just parsing out the pieces it needs?

    • 46 Comments

    Commenter acq responds (with expletive deleted), "the whole file is mapped into the process' memory only for version info that's certainly only a few kilobytes to be read?" Why not map only the parts that are needed? "I don't understand the necessity to map the whole file except that it was easier to write that code without thinking too much."

    That was exactly the reason. But not because it was to avoid thinking. It was to make things more secure.

    Back in the old days, the Get­File­Version­Info function did exactly what acq suggested: It parsed the executable file format manually looking for the file version information. (In other words, the original authors did it the hard way.) And it was the source of security vulnerabilities because malformed executables would cause the parser to "behave erratically".

    This is a common problem: Parsing is hard, and parsing bugs are so common that that there's an entire category of software testing focused on throwing malformed data at parsers to try to trip them up. The general solution for this sort of thing is to establish one "standard parser" and make everybody use that one rather than rolling their own. That way, the security efforts can be focused on making that one standard parser resilient to malformed data. Otherwise, you have a whole bunch of parsers all over the place, and a bad guy can just shop around looking for the buggiest one.

    And it so happens that there is already a standard parser for resources. It's known as the loader.

    The function Get­File­Version­Info therefore got out of the file parsing business (it wasn't profitable anyway) and subcontracted the work to the loader.

    Pre-emptive xpclient rant: "Removing the icon extractor for 16-bit DLLs was a mistake of the highest order, even worse than Component Based Servicing."

  • The Old New Thing

    Get your hex wrench ready, because here comes the Ikea bicycle

    • 14 Comments

    Ikea säljer elcyklar. Click through for two-image slide show.

    Ikea selling electric bicycles

    Forget furniture. Ikea is now launching, that's right, an electric bicycle.

    It goes under the name People-Friendly and costs around 6000 SEK ($900 USD).

    But only in Älmhult, Småland.

    People-Friendly has already received three design awards, including the IF Design Award, according to Ikea's press release.

    What distinguishes it from other electric bicycles is that the battery is hidden in the frame. That makes it look like a regular bicycle as well as lowering the center of gravity and makes the bicycle more stable.

    Performance is for the most part like other electric bicycles: It handles 6–7 Swedish miles (60–70 km, 35–45 US miles) on a charge, which takes 5–6 hours. The weight is 25 kg (55 pounds). The frame is aluminum and the engine is in front.

    Only in Småland

    The 5995 SEK cost of the bicycle may sound like a lot, but it's inexpensive for an electric bicycle.

    The biggest problem with the People-Friendly is that you can't buy it at regular Ikea stores.

    So far, the bicycle is sold only at the bargain department of the Älmhult Ikea.

    "Here is where we test new products. And this is a test product. We want to see how much interest there is and be sure that we can take care of the product, even after the purchase," says Daniela Rogosic, press officer for Ikea Sweden.

    She cannot say when it will begin being sold at general Ikea stores, but she confirms that interest has been strong for the bicycle during the month it has been available.

    Do you have to assemble it yourself like the furniture?

    "Yes, you put it together yourself in the classic Ikea way," says Daniela Rogosic.

    Fact sheet

    • Price: Around 7200 SEK ($1100 USD) in Austria
    • Material: Aluminum and steel (front fork)
    • Gears: 3
    • Weight: 25 kg
    • Battery: 36 V
    • Range: 60–70 km
    • Charge time: 5–6 hours
    • Top speed: N/A
    • Engine: 36 V, forward

    On the Web site for the Älmhult bargain department, it describes the bicycle as a three-speed, available in both men's and women's styles. Limit one per customer.

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Denial of service by high CPU usage

    • 40 Comments

    We received the following security vulnerability report:

    Windows is vulnerable to a denial of service attack that consumes 100% CPU.

    1. Use the following procedure to create a file that is enchanted by magic pixie dust: [...]
    2. Rename the file to TEST.EXE.
    3. Execute as many copies of the program as you have CPU cores.

    Observe that CPU usage climbs to 100% and never goes down. This a clear demonstration that Windows is vulnerable to a denial of service attack from magic pixie dust.

    The magic pixie dust is a red herring. This vulnerability report is basically saying "If you are allowed to run arbitrary programs, then it is possible to run a program that consumes all the available CPU."

    Well, duh.

    This is another case of if I can run an arbitrary program, then I can do arbitrary things, also known as MS07-052: Code execution results in code execution. (Or in the lingo of Internet memes, "High CPU is high.")

    Now, of course, if the magic pixie dust somehow allows a user to do things like access resources they do not have access to, or to circumvent resource usage quotas, then there would be a serious problem here, and if if the high CPU usage could be triggered remotely, then there is a potential for a denial-of-service attack. But there was nothing of the sort. Here's a much less complicated version of magic pixie dust:

    int __cdecl main(int, char **) { for (;;) { } /*NOTREACHED*/ }
    
  • The Old New Thing

    How to take down the entire Internet with this one weird trick, according to Crisis

    • 28 Comments

    According to the television documentary Crisis which aired on NBC last Sunday, a cyberattack took over the entire Internet.

    Timecode 13:00: "Anything connected to the Internet. Banking systems, power grid, air traffic control, emergency services. The virus has spread into them all."

    And the show includes an amazing journalistic scoop: A screen shot of the attack being launched! Timecode 11:40:

    文件上传
    Threads Progress Remaining Speed
    0:000> u eip-30 eip+20 notepad+0x5cfc: 01005cfc 0001 add [ecx],al 01005cfe 3bc7 cmp eax,edi 01005d00 7407 jz notepad+0x5d09 (01005d09) 01005d02 50 push eax 01005d03 ff15dc100001 call dword ptr [notepad+0x10dc (010010dc)] 01005d09 8b45fc mov eax,[ebp-0x4] 01005d0c 57 push edi 01005d0d 57 push edi 01005d0e 68c50000 push 0xc5

    That's right, my friends. This elite virus that shut down the Internet was an upload of Notepad!

  • The Old New Thing

    Cargo-cult registry settings and the people who swear by them

    • 14 Comments

    Two customers (so far) wanted to know how to increase the duration of taskbar balloon notifications on Windows Vista. (By the way, I gave the answer some time ago.)

    They claimed that on Windows XP, they were using the registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\Current­Version\Explorer\Tray­Notify, setting the value Balloon­Tip to a REG_DWORD specifying the number of seconds the balloon should appear. They wanted to know if this still worked in Vista.

    Heck, it didn't work even in Windows XP!

    That undocumented registry key actually controls whether the Windows XP taskbar should show the "To see the hidden icons, click this button" tip. It has nothing to do with how long the balloon stays on the screen.

    A quick Web search suggests that that particular setting has reached cult status, with everybody saying that the setting controls balloon duration, and nobody actually testing it. It's just a matter of faith.

    Even the sometimes-suggested trick of putting the registry key name in MSDN so searches can find it and direct users to the correct method wouldn't have helped, because this was the wrong registry key to begin with.

    (Remember, the answer is in the linked article.)

Page 5 of 427 (4,264 items) «34567»