奇怪的KERN_INVALID_ADDRESS例外?

问题描述

我正面临着一个奇怪的OC异常,看来我正在向已发布的地址发送消息,但是当我

  1. 尝试检查它是否为NULL,它仍然崩溃。
  2. 尝试调试或添加@try @catch,它捕获了所有内容,但是运行了几天,根本没有崩溃。

例外

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
VM Region Info: 0x10 is not in any region.  Bytes before following region: 4304617456
      REGION TYPE                      START - END             [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                        100934000-100a98000        [ 1424K] r-x/r-x SM=COW  ...x/APP

Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL,Code 0xb
Terminating Process: exc handler [18302]
Triggered by Thread:  22

下面的代码不严格,仅显示逻辑(代码一个串行调度队列中运行)

struct st_type {
    void *arg; 
};

static NSMutableDictionary *dictionary;
    
// init values
void init ()
{

    // there is a static dictionary to retain the object
    dictionary = [[NSMutableDictionary alloc]init];
    
    
    // an object reference saved in dictionary and a struct holds it's pointer
    NSObject *obj = [[NSObject alloc]init];
    
    struct st_type *st = malloc(sizeof(struct st_type));
    st->arg = (__bridge void *)obj;
    dictionary[@"cached"] = obj;
    
    // then the struct * passes to every where,I think it's safe because the object always in the dictionary.
    ...
}


// the only place to release the nsobject,so I think there is no chance to EXC_BAD_ACCESS,but ...
void release_object(struct st_type *st,NSObject obj){
    [dictionary removeObjectForKey:@"cached"];
    st->arg = NULL;
}

// some where to use the struct
void use_struct(struct st_type *st){
    if(st->arg == NULL){
        return;
    }
// if I add try catch,it never crashs
//    @try {   
    NSObject *obj = (__bridge NSObject*)st->arg;
    [obj description]; // crash here.
//    } @catch (NSException *exception) { print some log but it never reaches here... }
}

任何人都可以帮助我解决错误的下一步吗?

解决方法

如果我正确理解,您想将对Objective-C对象的引用存储为void *。例如,这与旧的contextuserInfo指针作为回调传递给工作表的用例类似。

有关示例,请参见ARC: __bridge versus __bridge_retained using contextInfo test case。我还假定您正在使用ARC(请阅读Casting and Object Lifetime Semantics)。

假设该结构的生存期比Objective-C对象的生存期更长,并且您在该结构中显式设置和释放了该对象,则不需要字典来进行内存管理。

一旦分配了结构和对象(分别使用malloc[[XX alloc] init]),就可以将对象的所有权移出ARC并使用{{1 }}投。

要使用该对象,请使用st->arg进行投射。这不会更改所有权。

准备释放对象时,请使用(__bridge_retained void *)进行投射,将所有权传回ARC。然后,您可以将(__bridge NSObject *)指针设置为(__bridge_transfer NSObject *)

总的来说,像这样:

void *