July, 2005

Larry Osterman's WebLog

Confessions of an Old Fogey
  • Larry Osterman's WebLog

    Cool article about Honk! at SCT in the local newspaper.

    • 6 Comments

    Last week, we got a phone call from the local newspaper (the Woodinville Weekly), they were doing a story on the SCT summer season and the kids in the Woodinville area that are appearing in shows there.

    We arranged for the reporter and Daniel to talk (a whole 'nother story, since Daniel left his phone at home), and they had what was apparently a quite pleasant conversation about the show.

    Yesterday, the web page with the interview went live, including some cool quotes from Daniel :)

     

    Now I just need to figure out a way of scrounging up enough issues for the grandparents.

     

  • Larry Osterman's WebLog

    Oh yeah - We shipped Beta1 today...

    • 14 Comments

    It feels wierd, because I don't normally jump on the "everyone in the world is blogging about it" bandwagon, but we shipped LH Beta1 today!

     

    Yipee!

    And Scoble has a great interview with Chris Jones up on channel 9.

    I thought the sour look that quickly flashed across Chris's face when Scoble mentioned my "We've RI'ed" post was cute.  I hope I don't find an email from Chris in my in-box tomorrow :)

     

  • Larry Osterman's WebLog

    Words I dislike - Policy

    • 11 Comments
    A while back, I wrote about how I disliked the word "Robustness" because it's meaning was so vague.

    Another word that I dislike (for similar reasons) is "Policy".  As I mentioned in my "We've RI'ed" post, I was asked to work on the "audio policy" infrastructure for Windows.

    The problem is that nobody knows (or knew) what "policy" means.  Some of the commenters on the previous post thought it had something to do with DRM (it doesn't).  On the other hand, the DRM system does have something called policies (they're content protection policies).

    Is "audio policy" the same thing as a group policy (a mechanism for applying system configuration in a domain)? Nope.

    What about power management - they have "policies" as well.  So does terminal services, so does TCP/IP.

    In fact, almost every part of the system has something that's called "policy".  In fact, a brief search of the Windows sources comes up with well over 5000 files with the word "policy" in them.  Now a lot of them have to do with settings that are managed via group policies, and a bunch of them come from test code, but there are still a lot of pieces of Windows that use things called "policy".  MSDN searches return hundreds and hundreds of pages for the word "policy".

    The root of my problem with the word "policy" is that it's almost impossible to have a conversation with someone and use the word - unless you lay out the ground rules ahead of time, it's really easy for people to get confused, especially if you're talking to someone from another team.

    Whenever I talk about the policy engine, if I'm talking to someone on my immediate team, they usually know what I'm talking about.  But as soon as I talk to someone on another team (even someone just down the hall), I have to spend 5 minutes describing what the policy engine does.

    Because the word has been used in so many contexts, for so many different things, it has essentially lost all meaning.

  • Larry Osterman's WebLog

    Making time go faster

    • 12 Comments
    I got the following email the other day from a reader:

    I cam across your post on pc time and thought you may have a quick answer. Thanks in advance.

    I have a program that is a reader that reads a log and sends a message to a second program that is the counter that counts the number of events it gets in a five minutes.

    Each entry in the log has a time stamp and is sequential. The log file reader reads the log and waits until it has hit the time in the time stamp (hour, minute and second) and then sends that event to the listner at that time. So to process a log for one day this set takes one day.

    I was wondering if there was some way that I could speed up the clock so I dont have to change the logic of either of the programs but have the task completed in say 4 hours (by spedding up the clock by 6 times).

    That's a fascinating idea, actually - is there a way of making time go faster?

    Whenever someone asks a question like this one, it's time to fall back on the tricks of the master.  Whenever he gets a question like this, Raymond always turns around and asks a question like "What if <x> could happen?" (or "What if two applications tried to do <y>?").

    So let's ask the question: "What if there was a way of speeding up the system clock so you don't have to wait so long?"

    What would that do to system timers?  If the entire system time is running faster, then they would also run faster. Would there be a consequence if something that's supposed to happen every 5 minutes all of a sudden started happening every 5 seconds?

    How about timeouts?  In other words, if I read some data from the disk and wait (with a timeout) for the disk read to complete, will that timeout run faster?  What happens the read timeout is 3 seconds and the disk normally takes 2 seconds for an I/O to complete?

    Monitor refresh frequency?  If your app is synchronized to the monitor refresh wait, and the application all of a sudden starts running twice as fast, what would be the results?

    If you're trying to make the system run faster than in real-time, it seems like all these would also speed up (otherwise you couldn't get the log playback operations to be faster, since these all run off the same timer).

    This is the crux of the problem - if you want your sleeps to go faster, then all the system events also need to be faster.  Unfortunately, there's all this physical hardware attached to the computer, and that physical hardware takes time to complete operations.  If you also have timeouts associated with those hardware operations, then you may introduce real problems.

    So the simple answer to the question is: "Not usually".  It might be possible to do something in a VM environment, and there are some utilities on the web that claim to be able to do this, but I wouldn't recommend them.

    Why can't you change the program that plays back the log to simply not wait as long?

  • Larry Osterman's WebLog

    We've RI'ed, part 2

    • 16 Comments

    In November of 2002, the SCP project (to build a controller ship for home automation) was winding down.  As happens when projects end-of-life, one of the things that management does is to divvy up the members of the team - sometimes the lead takes a bunch of the developers on the team with them to wherever they end up going, sometimes other leads take developers.

    I wasn't sure what I was going to be doing once SCP finished, until the dev manager for the Audio/Video Devices Group in eHome stopped by my office.

    He wanted me to move up onto the audio group to work on a project that would make UPnP devices full fledged Windows devices - basically by bridging the network space into the Windows devices hierarchy.  I worked on it for a couple of months, and developed a prototype, but it didn't really go very far.

    My lead on the team realized that this was going nowhere and he asked me if I was willing to help out by working on some "audio policy" work that the rest of his team was doing.

    I was cool with it (I'm usually cool with changes like that), so I went to work on the audio policy infrastructure in Windows Longhorn.

    My work was to be a relatively small part of a rather ambitious venture that the AVDG group was embarking on, but it was mine :)

    Along the way, I had a major work reset (I was asked to do the HTTP server for the Windows Media Connect product), two or three reorgs, a change in managers, and a major feature reset, but the heart of my little feature managed to remain in the plans throughout it all.  I've also picked up another feature along the way, but my heart has always been with the original feature.

    Well, on Friday of last week, we finally RI'ed our changes from our feature branch into the aggregation branch (for what those terms mean, see this PPT that Mark Lukovsky gave at Usenix several years ago).  This means that the features that I started working on back in 2002 are finally on their way to being part of the core Windows Vista product.  It's been a long two and a half years, and an even longer two and a half weeks (I went into 14 hour day work mode two weeks ago), but we're finally almost done!

    Last Wednesday, we had a review of the feature with Jim Allchin, and it was unbelievably successful - he suggested some useful changes to the UI, but overall, he absolutely loved the feature.

    I cannot describe how stoked I am about this.  When I first saw the UI, I couldn't decide if I wanted to shout in triumph or cry with joy seeing this new feature (I chose the shouting :)). 

    I'm still being coy about the details (sorry, I'd love to, but I've been told I can't talk about details, some of the rough ideas have been disclosed at several conferences in the past, but not the details) but for now, the train has left the station, our stuff is going in!

    WHOO HOO!!!

    Edit: Clearly I'm "details" oriented :)

  • Larry Osterman's WebLog

    Seattle Childrens Theater Summer Season

    • 6 Comments

    As I mentioned earlier, Daniel's appearing in SCT's summer season production of Honk!.  He'll be playing the part of Bullfrog, which is a mostly comic relief role (and he gets a killer song).

    The kids involved in the summer season performances have been working their tails off for most of the summer, and their hard work is starting to pay off, because SCT's Summer Season's is finally getting started.

    The SCT summer season performances typically run Thursday, Friday, and Saturday, of successive weeks, in two waves, one in late July, the second in late August.

     

    The first performances (of Homer's "Odyssey" and Louis Sachar's There's a Boy in the Girls' Bathroom") start on July 28th, running for three performances each (two evening, one matinee).

    Next up will be Jon Jory's "Love, Death and the Prom" and the musical "Honk!" running from August 4th through August 6th (the musicals run for four performances over three days).

    Rounding up the first wave is Shakespeare's "As You Like It" and Moliere's "Scapina" on August 11th through the 13th.  The Scapina performance is particularly interesting, it's being done in collabaration with the SCT Deaf Youth Drama Program - the show will be performed simultaneously in English and ASL.

     

    For the August wave, there are two shows - the first is a sequel to last summer's "Captain Blood", Sabatini's "The Return of Captain Blood", and an SCT original production by SCT's David Drummond and Don Flemming entitled "Tomorrow Was Better".

    "Tommorrow Was Better" is the product of the "Original Works" class at SCT - basically the kids in the class get together over a semester and come up with a play (and then perform the play on the last day of class).  Then the SCT wordsmiths take their work and turn it into an original play.

     

    These shows are absolutely worth seeing - SCT's productions are always top-notch, and the kids are absolutely amazing - there are some remarkable talents in these shows.  I know a bunch of the kids in Honk! (from other classes Daniel has taken over the years) and they're absolutely awesome.

    If it's possible, come see the shows, they're worth it.

    For people at Microsoft, drop me a line or stop by my office (it's in the address book) if you're interested - I've got ticket information and brochures in my office.

     

  • Larry Osterman's WebLog

    UUIDs are only unique if you generate them...

    • 28 Comments

    We had an internal discussion recently and the upshot of the discussion was that it turns out that some distributed component on the web appears to have used the UUID of a sample COM component.

    Sigh.

    I wonder sometimes why people do this.  It's not like it's hard to run uuidgen and then copy the relevent GUIDs to your RGS file (and/or IDL file, or however it is you're defining and registering your class).

    I guess the developers of the distributed component figured that they didn't have to follow the rules because everyone else was going to follow them.

    And, no, I don't know what component it was, or why they decided to copy the sample.

    So here's a good rule of thumb.  When you're designing a COM component, you should probably use UUIDGEN (or UuidCreate()) to generate unique (and separate) GUIDS for the Interface ID, Class ID, and Library ID and App ID.

     

  • Larry Osterman's WebLog

    Clippy Lives!

    • 6 Comments

    My boss just sent me this blog post from a friend of his.  The language is a bit rough, but I came close to spewing soda (pop for those of you in Piksburgh, coke for those of you in Atlanta) all over my monitor.

    http://www.caseytime.com/index.cgi/2005/07#mom_and_paperclip

     Edit: Hold on, the link's dead - trying to figure out what happened.

    Edit2: I'm not going to pull this article (because I'd have to explain what happened), it was quite funny, but I've not heard back from Casey so...  Sorry for the false alarm :(

    Edit3: Link's up again.  Thanks Casey :)

    Edit4: Casey's Noel's friend :)

     

  • Larry Osterman's WebLog

    Remember the blibbet

    • 36 Comments

    There was a thread on Channel9 that got me to remember the blibbet.

    "The blibbet?"  What on earth is a blibbet?

    The blibbet is the "O" in the 2nd Microsoft logo:

    Those of us who've been at Microsoft for a long time all have fond memories of the blibbet, which was cruely killed off in a fit of corporate ire in 1987.  Not only was it our corporate logo, but if you look at Microsoft binders from the time (1982-1987), you'll see that the blibbet is used as a watermark on it.

    At one point, I had a "save the blibbet" button, but unfortunately, I can't seem to find it (otherwise I'd post a photo of it).

    Periodically you find reminders of the blibbet around campus.  For example, the cafeterias used to offer a "Blibbet Burger" - a double cheeseburger with bacon, IIRC.

    I miss the blibbet :)  Somehow, it reminds me of Herbie (or any other VW bug) - cute and friendly :)

    Edit: Added more after a little bird sent me the image..

    When Microsoft announced that the would be retiring the blibbet, a number of employees mounted a fruitless "Save the Blibbet" campaign to retain the corporate icon.

    Unfortunately, the suits won :(

     

  • Larry Osterman's WebLog

    Beware of the dancing bunnies.

    • 57 Comments

    I saw a post the other day (I'm not sure where, otherwise I'd cite it) that proclaimed that a properly designed system didn't need any anti-virus or anti-spyware software.

    Forgive me, but this comment is about as intellegent as "I can see a worldwide market for 10 computers" or "no properly written program should require more than 128K of RAM" or "no properly designed computer should require a fan".

    The reason for this is buried in the subject of this post, it's what I (and others) like to call the "dancing bunnies" problem.

    What's the dancing bunnies problem?

    It's a description of what happens when a user receives an email message that says "click here to see the dancing bunnies".

    The user wants to see the dancing bunnies, so they click there.  It doesn't matter how much you try to disuade them, if they want to see the dancing bunnies, then by gum, they're going to see the dancing bunnies.  It doesn't matter how many technical hurdles you put in their way, if they stop the user from seeing the dancing bunny, then they're going to go and see the dancing bunny.

    There are lots of techniques for mitigating the dancing bunny problem.  There's strict privilege separation - users don't have access to any locations that can harm them.  You can prevent users from downloading programs.  You can make the user invoke magic commands to make code executable (chmod +e dancingbunnies).  You can force the user to input a password when they want to access resources.  You can block programs at the firewall.  You can turn off scripting.  You can do lots, and lots of things.

    However, at the end of the day, the user still wants to see the dancing bunny, and they'll do whatever's necessary to bypass your carefully constructed barriers in order to see the bunny

    We know that user's will do whatever's necessary.  How do we know that?  Well, because at least one virus (one of the Beagle derivatives) propogated via a password encrypted .zip file.  In order to see the contents, the user had to open the zip file and type in the password that was contained in the email.  Users were more than happy to do that, even after years of education, and dozens of technological hurdles.

    All because they wanted to see the dancing bunny.

    The reason for a platform needing anti-virus and anti-spyware software is that it forms a final line of defense against the dancing bunny problem - at their heart, anti-virus software is software that scans every executable before it's loaded and prevents it from running if it looks like it contain a virus.

    As long as the user can run code or scripts, then viruses will exist, and anti-virus software will need to exist to protect users from them.

     

  • Larry Osterman's WebLog

    What's wrong with this code, part 14 - the answers

    • 16 Comments

    Yesterday's post was a classic example of Joel Spolsky's Law of Leaky Abstractions.

    Why?  Well, because it was an example of conflicting contracts.

    In COM, the contract for an API is defined  by the APIs interface.  In this case, it was:

    [
        object,
        uuid("0A0DDEDC-C422-4BB3-9869-4FED020B66C5"),
        pointer_default(unique)
    ]
    __interface IFoo : IUnknown
    {
        HRESULT GetFooConfig([out] struct FooConfig **ReturnedFooConfig);
    };

    A straightforward contract - there's a function named "GetFooConfig" that fills in a pointer with a pointer to a FooConfig structure.  Nothing exciting there.

    In this case, the author of the interface chose to return a pointer to a global variable for the output value.  Again, nothing exciting, there's no reason that it wouldn't work - if the _GlobalFooConfig variable is constant, there aren't even multi-threaded access issues (it could be put in a read-only section, for example).

    But there's a problem.  The thing is that COM (actually the RPC runtime library, but it's easier to blame COM) has an additional requirement for [out] pointers.  This requirement is that if the type of an [out] parameter isn't a scalar quantity (in other words if it's a structure or anything more complicated than a int or float), then the memory pointed to by the [out] parameter needs to be allocated either by MIDL_user_allocate (for RPC) or CoTaskMemAlloc (for COM).

    This is a leaky abstraction - the abstract interface says nothing about this additional requirement, so the COM requirement leaks through to the implementation.  And what's worse, the leak doesn't show up until the RPC marshaller gets involved in the process - until that happens, the interface works perfectly.

    So why did this work until the new tests were rolled out?  Well, it was because up until then, the COM object had always been executed in-proc.  But the new test case instantiated the COM object out-of-proc and the RPC runtime library tried to marshal the code and...  Boom.

    Kudos:

    First off, bao caught a stupid mistake in GetFooConfig() that was unintentional.

    ThaleseC correctly called out the fact that we were returning a static variable, but the pieces didn't get fully put together until vrk caught the marshaling issue.

    Ralf's comment about not checking for a null ReturnedFooConfig is interesting - the contract for GetFooConfig specifies that the ReturnedFooConfig parameter isn't optional (because it's flagged as [out]).  The RPC runtime guarantees that ReturnedFooConfig is always valid.  And in-proc, crashing on a null parameter is probably as useful as checking for a null pointer - that way programming errors on the part of the client of the interface get caught quickly.

    Other comments: Alex pointed out that this wasn't pure ansi C++ because it used the Microsoft C++ annotation extensions.  He's right.

    Mike pointed out that my stylistic choice of _Xxx for global variables (and member variables) conflicts with the C++ standard - he's right, they are reserved.

    rederick Slijkerman pointed out that CFoo should derive from IUnknown.  This is true, and it happens already, since IFoo derives from IUnknown.  Adding an explicit interface isn't necessary (and can potentially lead to ambiguity)

    Finally, mirobin commented on the fact that the call returns a pointer to a data structure - as I pointed out, this isn't necessarily a problem, assuming that the rules for the FooConfig are clearly understood.

     

    On a related note, I'm insanely busy right now so I suspect I'll be rather short on new posts for the next week or so...

  • Larry Osterman's WebLog

    What's wrong with this code, part 14

    • 32 Comments
    Keeping up with the "theme" of COM related bad code examples, here's another real-world example.  To avoid any ATL confusion, it's 100% pure C++.

    Our test team rolled out a new set of tests last week and immediately hit this one.  The funny thing is that the code in question had worked  without flaw for two years before this.

    Obviously this has been abstracted to the point of ridiculousness, there's just enough here to demonstrate the bug...

    struct FooConfig
    {
        int _Value1;
        int _Value2;
    };

    [
        object,
        uuid("0A0DDEDC-C422-4BB3-9869-4FED020B66C5"),
        pointer_default(unique)
    ]
    __interface IFoo : IUnknown
    {
        HRESULT GetFooConfig([out] struct FooConfig **ReturnedFooConfig);
    };

    FooConfig _GlobalFooConfig = { 1, 2};

    class CFoo: public IFoo
    {
        LONG _refCount;
    public:
        CFoo() : _refCount(1) {};

        // IFoo
        HRESULT GetFooConfig(FooConfig **ReturnedFooConfig)
        {
            *ReturnedFooConfig = &_GlobalFooConfig;
            return S_OK;

        }

        // IUnknown
        virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppUnk)
        {
            HRESULT hr=S_OK;
            *ppUnk = NULL;
            if (iid == __uuidof(IFoo))
            {
                AddRef();
                *ppUnk = reinterpret_cast<void *>(static_cast<IFoo *>(this));
            }
            else if (iid == IID_IUnknown)
            {
                AddRef();
                *ppUnk = reinterpret_cast<void *>(static_cast<IUnknown *>(this));
            }
            else
            {
                hr = E_NOINTERFACE;
            }
            return hr;
        }
        virtual ULONG STDMETHODCALLTYPE AddRef(void)
        {
            return InterlockedIncrement(&_refCount);
        }
        virtual ULONG STDMETHODCALLTYPE Release(void)
        {
            LONG refCount;
            refCount = InterlockedDecrement(&_refCount);
            if (refCount == 0)
            {
                delete this;
            }
            return refCount;
        }
    };

    This one's pretty straighforward, and I expect that people will see the problem right away.  So I'm going to raise the bar a bit - to get full credit, you not only have to explain not only what the problem is, but also why we'd never seen a problem with this code before.

    And, as always, kudos and mea culpas on Monday.

    Edit: Fixed return value from GetFooConfig.

  • Larry Osterman's WebLog

    What I did on the 4th of July...

    • 23 Comments

    I originally wasn't going to write this up, but Valorie thought it was a cute story.

    I need to describe some terminology first.  Here on the Windows team, we call a full build of Windows a "timebuild" - normally, you don't build the entire Windows product to make a change to your component - you typically just have to rebuild the individual DLL (or EXE) and test it in isolation.

    But before you check any new feature, especially a feature that affects multiple major subsystems of Windows, you need to do a full build (among other reasons, to insure that any changes you made to headers don't break other components in Windows). 

    One other thing that a timebuild provides is a baseline for the test team.  You see, the test team can run tests with privately built bits (from the developer) and they can get a reasonable degree of confidence in the fix, but for a significant change, it's better to have a complete build of the world - that ensures that the testers are testing a system that's as close to a real system as they can possibly get.

    Anyway, I'm close to finishing up two of my features for Longhorn, so it was time to do the timebuild.  I started it on Friday, found some issues and fixed them, and left for the weekend, figuring I'd check up on the timebuild over the weekend (not surprisingly, it takes more than one or two hours to build all of Windows).

    I was busy on Saturday, but didn't worry about it.

    Sunday morning, I decided to check on the timebuild, so I RAS'ed in to check on the build.

    The RAS connection worked just fine, but during the post connect security checks, I got a wierd error, something I'd never seen before (fatal execution error or something like that).

    So it was time to get on the horn with Helpdesk and see if they had any idea.  One of the nice things about working for a big company is that they have a helpdesk that's staffed 7x24, even on holiday weekends.  So I got on the phone and waited for about 10 seconds for the tech to pick up.

    She worked me through a couple of suggestions, none of which worked, so she escalated the call up the chain.  While this was going on, I drove into work and fixed a couple of problems and restarted the timebuild.

    Later that afternoon, we had a BBQ at some friends, so I didn't bother trying again.  On the other hand, I enjoyed myself immensely at the BBQ, so it was worth it.

    On Monday morning, I had an email from helpdesk waiting for me.  It turns out that since my machine at home is joined to a corp domain one of the scripts was depending on a tool that hadn't been pushed to my machine yet (classic chicken and egg problem - the tool would be pushed when I connected to the domain, but since I couldn't RAS in, the tool couldn't be pushed to my machine).  Silly, but stuff like that happens.

    The suggestion from helpdesk was that I unjoin the domain and re-join the domain.  They were very careful to remind me to ensure that I knew the password for the administrator account on the machine since my domain account would no longer work for logon (this is the only one of my machines on which I routinely run as an admin, because our RAS logon process requires admin access - there are workarounds but I'm lazy :().

    It turns out that I HAD forgotten the password for the local administrator account.  So, being the bright boy, I reset the password to something known and unjoined the domain.

    I then logged in as the administrator account and tried to connect to rejoin the domain.  And I got an error.

    That was weird, the error was the exact same error you'd expect to get when you're not running as an admin.

    So I did a "NET LOCALGROUP ADMINISTRATORS" from the command line.

    There was only one entry, "Sharron".

    Oh crud.  Then the memories came flooding back.  Five years ago, when I set this machine up, I had just gotten DSL, and didn't have a hardware firewall, and the machine was running W2K, so it didn't have a built-in firewall.  I was running ZoneAlarm at the time, but I wanted an additional level of security (stupid, I know, but that was 5 years ago).  So I tried to set up a sort-of "honeypot" - I renamed the administrator account to be "Sharron" and created a new account in the guests group (this was on W2K) called Administrator.

    Not only that, but I couldn't remember the password on the "Sharron" account.  So now I have a machine on which the only account that I have a password is the guest account.

    The phrase "Hoist by my own petard" comes to mind.  And I was SO PROUD of myself for remembering to ensure that I knew the administrator account password.

     

    And now, the mistakes start piling on fast and furious.  For some reason, instead of trying to boot to the recovery console and resetting the password on the Sharron account, I decided to re-install Windows XP.

    But, of course, the only copy of Windows XP I had was a Windows XP RTM disk.  This isn't a problem because I trust the hardware firewall to keep my machine safe while I install XP and download SP2 onto it.

    No big deal, right?

    Wrong.

    About 2/3rds of the way through the installation, I get a popup about the setup failing.  The setup log doesn't have anything reasonable in it, and the setup is past the point where you can undo the setup.

    The installation of Windows on that machine is toast.  I'm swinging in the wind here, folks.  The old installation is toast, the new installation didn't work, I don't know what to do.

    So I hauled the disk out, and restarted the installation, this time doing a clean installation.  Any apps will have to be reinstalled, etc, but at least I didn't have to reformat the drive.

    Oh yeah, the product key.  That's right.  This machine is owned by Microsoft, I got the product key from Microsoft, and I don't have original media for it (I do for all my other machines, just not this one, since it's Microsoft's machine).  The product key's sitting on a server at work, if I could RAS into work, I could get it...

    Fortunately, my other machine is more than capable of running RAS (it's the "good" machine).  So I installed RAS on my other machine, dialed in, and got the product key off the server at work.

    Installation continued on the newly-reinstalled machine, but for some reason XP RTM didn't recognize the NVidia TI-4400 adapter in the machine (I think the TI4400 came after XP RTM).  I installed the antivirus software and SP2, downloaded all the security patches, and I was good to go.

    But even though XP recognized the NVidia adapter, it STILL didn't stick.  It wasn't until I downloaded the latest WHQL drivers from NVidia that the driver stuck.

    At this point, it's about 4PM on Monday, and I'm back to where I was back on Sunday Morning

    So I reinstalled RAS and try to connect, and...

    I get a different error code, this one coming from the smartcard reader.  I've still not resolved that one (tonight, if I have the time).

    Sometimes, it's just not worth waking up in the morning.

    On the other hand, the timebuild worked great, I installed it on my test machine when I came into work yesterday and the feature worked!  Now I'm doing a timebuild of my OTHER feature, when that one completes (in about an hour or so), I'll be installing that to ensure that that works.  And I finished the latest Misty Lackey novel (Sanctuary) and a Judge Dee novel (The Chinese Bell Murders, by Robert van Gulik).

    So the day wasn't a total loss.  And I haven't had to reformat the C drive (yet). 

    But it sure was annoying.

  • Larry Osterman's WebLog

    Should developers learn crypto?

    • 20 Comments
    Over the weekend, Paul Maher posted an article in which he asked if developers needed to understand cryptography.

    I responded in his comments, but it needs a bit more detail than I provided in the comments.

    I'm all for developers learning about crypto.  But developers also need to understand that it's all well and good for them to understand crypto, as long as they don't ever actually attempt to IMPLEMENT crypto.

    Because if they do attempt to implement crypo, they're going to get it wrong.

    There have been WAY too many examples of this.  From the initial Microsoft PPTP implementation, to Netscape's SSL implementation (I can't find the reference right now, but the original Netscape SSL implementation used an easily discovered initialization vector which rendered the encryption essentially useless), to the authentication scheme for Dark Age of Camelot, the list goes on.  All of the above issues have long been fixed, but that doesn't matter, because they all share a common flaw.

    The root cause of each of these failures was a developer that thought they understood crypto but didn't REALLY understand it.

    Whenever a developer decides that they can implement crypto, they need to stop and rethink what they're doing, because they ARE going to get it wrong.

    It makes sense for a developer to understand the relative strengths and weaknesses of different crypto solutions, to understand why SHA-1 is better than MD5, etc.

    But developers also need to understand that doing cryptography right requires special skills that most developers don't have.

    Instead of attempting to roll their own crypto, they should rely on the cryptographic solutions that are built into the platform (CryptoAPI is your friend).  If you stick to existing implementations, you're less likely to mess it up.

    And whatever you do, don't attempt to roll your own authentication scheme - for every way you can mess up crypto, there are a dozen ways you can mess up authentication.  See this wonderful dialog (I've referenced it before) for an example of the kind of pitfalls you can hit designing an authentication system.

    So it makes sense for a developer to LEARN crypto.  But developers shouldn't believe that they can IMPLEMENT crypto.  Because (with very few exceptions) they can't.

    So feel free to learn about crypto - there's a lot of great stuff there.  I highly recommend Simon Singh's "The Code Book" (or the YA version of the same book)  And of course Schneier's Applied Cryptography is a classic.

    But recognise that just because you've read a couple of books about cryptography, in general you're not competent to actually implement cryptography.

     

  • Larry Osterman's WebLog

    Private Destructors

    • 17 Comments
    Yesterday, I mentioned that Michael Ruck had complained that I'd made the destructor on my CFooBase class private, and he wondered why on earth I had done it.

    Skywing answered in the comments but it bears a bit more discussion.

    The simple answer to why I made the destructor private was that I didn't want anyone to be able to destroy the object.

    ????

    That's right.  You see, CFooBase is a reference counted objects.  And you NEVER, EVER want to allow someone to delete a reference counted object.

    This is because you don't own the lifetime of the reference counted object.  Really, you don't.  You own the lifetime of your reference to the object, but you have no way of controlling who else is taking a reference to the object.  So the object may live well after you're done with it.

    For example, consider the following case:

    void MyFunction(void)
    {
        CFooBase *myFoo;

        myFoo = new CFooBase();
        <Do Some Stuff>
        delete myFoo;
    }

    Seems pretty straightforward, right?

    Well, no.  The reason is that you have no idea what happened in the <Do Some Stuff> section.  For example, consider:

    void MyFunction(void)
    {
        CFooBase *myFoo;

        myFoo = new CFooBase();
        hr = RegistrationFunction->RegisterForNotifications(myFoo);  // RegistrationFunction takes a reference.
        <Do Some Stuff>
        hr = RegistrationFunction->UnregisterForNotifications(myFoo); // Releases the reference taken earlier
        delete myFoo;
    }

    What's wrong here?  Well, what happens if a notification was being processed during the call to UnregisterForNotifications?  In that case, the notification logic would take ANOTHER reference to the myFoo object (to ensure that the object remains alive during the duration of the callback).  But by deleting the myFoo directly, you're deleting the object out from under the registration function.

    If, on the other hand, you make the destructor for myFoo private, then the call to delete myFoo returns an error, which forces you to rewite the code to look like:

    void MyFunction(void)
    {
        CFooBase *myFoo;

        myFoo = new CFooBase();
        hr = RegistrationFunction->RegisterForNotifications(myFoo);  // RegistrationFunction takes a reference.
        <Do Some Stuff>
        hr = RegistrationFunction->UnregisterForNotifications(myFoo); // Releases the reference taken earlier
        myFoo->Release();    // Remove my reference to the myFoo
    }

    In other words, making the destructor private forces you to use the correct release pattern for refcounted object.

    Of course, the next problem that comes up is the question of deterministic finalism - if the object in question is holding some external resource open and you need to ensure that it's closed its resources.

    Well, the CLR IDisposable pattern comes in quite handy here.  That allows the caller to notify the object that it's done with the object.  Of course, it's also responsible for dealing with the consequences...

    The bottom line is that once you decide to use reference counted objects, you don't control the lifetime of the object, all you do is control the lifetime of a reference to the object.  And declaring the destructor private forces you to recognise this.

Page 1 of 1 (15 items)