Replace -[NSKeyedUnarchiver unarchiveObjectWithData:] so it doesn't crash on corrupt archive
Replace -[NSKeyedUnarchiver unarchiveObjectWithData:] so it doesn't crash on corrupt archive
- Subject: Replace -[NSKeyedUnarchiver unarchiveObjectWithData:] so it doesn't crash on corrupt archive
- From: Jerry Krinock <email@hidden>
- Date: Thu, 2 Jul 2009 20:17:13 -0700
If -[NSKeyedUnarchiver unarchiveObjectWithData:] is handed a corrupt
archive, it raises an exception AND crashes the program. I find this
to be very annoying since, almost always, archives come from files or
network sources where corruption is possible. Therefore, I have
always protected this invocation in a try/catch block.
As I was about to do this for about the fifth time this year, I
decided to use the Method Replacement feature of Leopard to replace
this method, once and for all, with one that wouldn't crash. I
understand that Method Replacement should not be done casually because
any plug-in code and even Cocoa itself will use the replaced method.
However, I can't think of any usage where a crash would be required
behavior.
It seems to work fine, after 10 minutes of testing. Does anyone see
any problem with this?
Sincerely,
Jerry Krinock
#import <Cocoa/Cocoa.h>
/*!
@brief Improvements to NSKeyedUnarchiver
@details Method +unarchiveObjectWithData: has been replaced so that
instead of raising an exception and crashing if given a corrupt
archive,
it just returns nil. Also, another method has been added which
returns the exception.
*/
@interface NSKeyedUnarchiver (CatchExceptions)
/*!
@brief Like unarchiveObjectWithData:, except it returns the
exception by reference.
@param exception_p Pointer which will, upon return, if an
exception occurred and said pointer is not NULL, point to said
NSException.
*/
+ (id)unarchiveObjectWithData:(NSData*)data
exception_p:(NSException**)exception_p ;
@end
#import "NSKeyedUnarchiver+CatchExceptions.h"
#import <objc/runtime.h>
@implementation NSKeyedUnarchiver (CatchExceptions)
+ (id)unarchiveObjectWithData:(NSData*)data
exception_p:(NSException**)exception_p {
id object = nil ;
@try {
// Note: Since methods were swapped, this is invoking the
original method
object = [NSKeyedUnarchiver
replacement_unarchiveObjectWithData:data] ;
}
@catch (NSException* exception) {
if (exception_p) {
*exception_p = exception ;
}
}
@finally{
}
return object ;
}
+ (void)load {
// Swap the implementations of +unarchiveObjectWithData: and
+replacement_unarchiveObjectWithData:.
// When the +unarchiveObjectWithData: message is sent to the
NSKeyedUnarchiver class object,
// +replacement_unarchiveObjectWithData: will be invoked
instead. Conversely,
// +replacement_unarchiveObjectWithData: will invoke
+unarchiveObjectWithData:.
Method originalMethod = class_getClassMethod(self,
@selector(unarchiveObjectWithData:)) ;
Method replacedMethod = class_getClassMethod(self,
@selector(replacement_unarchiveObjectWithData:)) ;
method_exchangeImplementations(originalMethod, replacedMethod) ;
}
+ (id)replacement_unarchiveObjectWithData:(NSData*)data {
return [self unarchiveObjectWithData:data
exception_p:NULL] ;
}
@end
TEST CODE:
int main (int argc, const char * argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// Try to unarchive your bash profile
// This ain't gonna be able to unarchive
NSData* data = [NSData dataWithContentsOfFile:[NSHomeDirectory()
stringByAppendingPathComponent:@".bash_profile"]] ;
NSLog(@"Your bash profile data is %d bytes.", [data length]) ;
id whatever ;
// Try it using the normal method
whatever = [NSKeyedUnarchiver unarchiveObjectWithData:data] ;
NSLog(@"1. unarchived whatever = %@", whatever) ;
// Try it using the improved method that returns the exception:
NSException** exception ;
whatever = [NSKeyedUnarchiver unarchiveObjectWithData:data
exception_p:&exception] ;
NSLog(@"2. unarchived whatever = %@", whatever) ;
NSLog(@"exception = %@", exception) ;
[pool release] ;
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden