6

意図的にEXC_BAD_ACCESS. NSObject読み取り専用の仮想メモリ ページへの書き込みをトリガーする。理想的には、 をキャッチEXC_BAD_ACCESSし、仮想メモリ ページを読み書き可能としてマークし、通常どおりに実行を継続させたいと考えています。これは可能ですか?私が書いたコードEXC_BAD_ACCESSは以下のとおりです。

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);
}
4

1 に答える 1

3

答えがあるdarwin-dev の投稿を見つけました!

警告

この答えには大きな欠点があります。私のデバッガーは、マッハ例外スレッド以外のスレッドでは動作しません。他のスレッドにブレークポイントを設定すると、Xcode5 がハングアップしました。強制終了しなければなりませんでした。私のcatch_exception_raise関数内では、うまくいきました。私はこれについて LLDB の人々に尋ねました。

終了警告

このコードは、答えの骨組みです。(フォローアップによると)エラーを回復可能にするために何かをする必要があるため、無限ループになります。私の場合、ページを読み書き可能としてマークする必要があります。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <pthread.h>
#include <assert.h>
#include <mach/mach.h>

kern_return_t
catch_exception_raise(mach_port_t exception_port,
                      mach_port_t thread,
                      mach_port_t task,
                      exception_type_t exception,
                      exception_data_t code_vector,
                      mach_msg_type_number_t code_count)
{
    fprintf(stderr, "catch_exception_raise %d\n", exception);
    return KERN_SUCCESS;  // loops infinitely...
}

void *exception_handler(void *arg)
{
extern boolean_t exc_server();
mach_port_t port = (mach_port_t) arg;
mach_msg_server(exc_server, 2048, port, 0);
abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)
}

void setup_mach_exception_port()
{
static mach_port_t exception_port = MACH_PORT_NULL;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);
mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
pthread_t returned_thread;
pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);
}

void test_crash()
{
    id *obj = NULL;
    *obj = @"foo";
}

int main(int argc, char** argv)
{
    setup_mach_exception_port();
    test_crash();
    return 0;
}

これは動作する私の新しいコードです:

WeakTargetObject.h (ARC)

@interface WeakTargetObject : NSObject
@property (nonatomic, weak) NSObject *target;
@end

WeakTargetObject.m (ARC)

@implementation WeakTargetObject
@end

main.m (MRR)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <pthread.h>
#include <assert.h>
#include <mach/mach.h>

static char * mem = NULL;

kern_return_t
catch_exception_raise(mach_port_t exception_port,
                      mach_port_t thread,
                      mach_port_t task,
                      exception_type_t exception,
                      exception_data_t code_vector,
                      mach_msg_type_number_t code_count)
{
  fprintf(stderr, "catch_exception_raise %d, mem: %p\n", exception, mem);
  kern_return_t success = vm_protect(mach_task_self(),
                                     (vm_address_t)mem,
                                     vm_page_size,
                                     0,
                                     VM_PROT_DEFAULT);
  fprintf(stderr, "switched to read-write: %d\n", success);
  return KERN_SUCCESS;
}

void *exception_handler(void *arg)
{
extern boolean_t exc_server();
mach_port_t port = (mach_port_t) arg;
mach_msg_server(exc_server, 2048, port, 0);
abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)
}

void setup_mach_exception_port()
{
static mach_port_t exception_port = MACH_PORT_NULL;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);
mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
pthread_t returned_thread;
pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);
}

- (void)main {
  setup_mach_exception_port();
  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,
             // zero means don't set VM_PROT_READ as the maximum protection
             // one means DO set VM_PROT_READ as the maximum protection
             // we want zero because the if VM_PROT_READ is the maximum protection
             // we won't be able to set it to VM_PROT_DEFAULT later
             0,
             VM_PROT_READ);

  // triggers EXC_BAD_ACCESS when objc runtime 
  // tries to nil weakTargetObject.target
  [weakTargetObject release]; 
  NSLog(@"expect nil. weakTargetObject.target: %@", weakTargetObject.target);
}
于 2013-10-18T05:26:09.070 に答える