I'm intentionally causing an EXC_BAD_ACCESS
. By triggering a write to an NSObject
in a read-only virtual memory page. Ideally, I'd like to catch EXC_BAD_ACCESS
, mark the virtual memory page as read-write and have execution continue as it normally would have. Is this even possible? The code I've written to cause the EXC_BAD_ACCESS
is below.
WeakTargetObject.h (ARC)
@interface WeakTargetObject : NSObject
@property (nonatomic, weak) NSObject *target;
@end
WeakTargetObject.m (ARC)
@implementation WeakTargetObject
@end
main.m (MRR)
- (void)main {
char *mem = NULL;
vm_allocate(mach_task_self(), (vm_address_t *)&mem, vm_page_size, VM_FLAGS_ANYWHERE);
NSLog(@"mem: %p", mem);
WeakTargetObject *weakTargetObject = objc_constructInstance([WeakTargetObject class], (void *)mem);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSObject *target = [[NSObject alloc] init];
weakTargetObject.target = target;
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
NSLog(@"expect non-nil. weakTargetObject.target: %@", weakTargetObject.target);
[pool drain];
vm_protect(mach_task_self(),
(vm_address_t)mem,
vm_page_size,
1,
VM_PROT_READ);
// triggers EXC_BAD_ACCESS when objc runtime
// tries to nil weakTargetObject.target
[weakTargetObject release];
NSLog(@"expect nil. weakTargetObject.target: %@", weakTargetObject.target);
}
I found a darwin-dev post that has the answer!
WARNING
This answer has a major downside. My debugger wouldn't work in any thread other than the mach exception thread. Putting a breakpoint in any other thread caused Xcode5 to hang. I had to force-quit it. Inside my
catch_exception_raise
function, it worked fine. I asked the LLDB folks about this.END WARNING
This code is the skeleton of the answer. It will infinite loop, because (according to the follow-up) you need to do something to make the error recoverable. In my case, I need to mark the page as read-write.
This is my new code that works:
WeakTargetObject.h (ARC)
WeakTargetObject.m (ARC)
main.m (MRR)