multipart-message nevyn bengtsson's blog

featured articles 🦄, about, archive, tags

NSFileHandle Considered Harmful [Updated]

Update 20090627: This bug has been fixed in 10.6. I’d still only recommend using it for very simple cases, but at least it works now!

NSFileHandle has a bug where the calling thread will lock up indefinitely if a data of size >4096 is requested. Reduced case:


#import 

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor:fileno(fopen("/dev/random", "r"))];
    
    NSLog(@"Reading 4096 bytes... This will succeed.");
    [fh readDataOfLength:4096];
    NSLog(@"Reading 4097 bytes... This will lock for infinity");
    [fh readDataOfLength:4097];
    NSLog(@"This will never be printed.");
    
    [fh closeFile];
    [fh release];

    [pool drain];
    return 0;
}

(Warning: running this program might lock up your computer; killing the rogue process is difficult as NSFileHandle will read an infinite amount of data from /dev/random, swapping out your OS.)

This is extra dangerous if your read length is dynamic, such as in a protocol where the first incoming bytes defines how long the upcoming chunk to read is.

Solution: Use the C API for working with file descriptors instead, such as read() and write(). A file descriptor can be extracted with [NSFileHandle fileDescriptor] if you receive one from another API.

(This bug has been reported.)

Tagged cocoa, nsfilehandle, bugs