Mystery Bug: Heisenberg’s Uncertainty Principle

I’ve spent the past couple hours going crazy over a bug. It’s the type of bug where it breaks except for when you look at it, in which case, it works all the time. Don’t believe me? Compile the following program:

#import <Foundation/Foundation.h>

int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool;
NSString *path;
NSDictionary *dict;

pool = [[NSAutoreleasePool alloc] init];
path = [NSString stringWithUTF8String:argv[1]];

dict = [[NSFileManager defaultManager] fileAttributesAtPath:path
traverseLink:NO];

// The busy flag will be NULL if you comment out the next line.
//NSLog(@"DICT: %@", dict);

NSLog(@"Creation: %@", [dict objectForKey:NSFileCreationDate]);
NSLog(@"Busy: %@", [dict objectForKey:NSFileBusy]);
}

By the way, I know I’m not releasing the pool.

Now, take a file and set its busy flag. You can do this as follows:

/Developer/Tools/SetFile -a Z some file

Then run my little program with some file as an argument. Notice how the busy flag is null?

Well, let’s see what’s in the dictionary passed back to us to find out what’s going wrong here. Edit the program above to uncomment the NSLog statement. Run it again. Notice how the busy flag is now set?

It appears that the dictionary is half-initialized until you happen to call certain methods (-allKeys works as well as -description). I haven’t tested every key but it does seem to be peculiar to NSFileBusy.

For the time being, I’m going to switch to Carbon to do this but I’d love to hear theories (or even facts) on what’s going on here. Let the wild speculation begin.

Oh, and since I brought up Heisenberg, I can’t let an opportunity to include an artful rendering of a dead cat pass by so here: