【问题标题】:weird KERN_INVALID_ADDRESS exception?奇怪的 KERN_INVALID_ADDRESS 异常?
【发布时间】:2020-10-05 14:19:18
【问题描述】:

我正面临一个奇怪的 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... }
}

谁能帮我解决这个错误接下来我能做些什么?

【问题讨论】:

  • 这是 ObjC 中的非典型模式。你想达到什么目的? st_type 的目的是在 dictionary 处理内存管理时传递一个无类型的对象吗?可能还有其他方法可以做到这一点。
  • 它是示例,在项目中不是真实的。这样写的代码是因为它是 oc 和 c 库之间的桥梁。 st_type 是一个由 c lib 管理的结构体。
  • obj 的生命周期是否与结构的生命周期相关联? dictionary的目的是什么?
  • 字典是oc对象的存储,防止释放,struct的生命周期比oc对象长,但是当oc需要dealloc时,会将struct的指针设置为NULL。

标签: objective-c exc-bad-access


【解决方案1】:

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

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

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

一旦分配了结构和对象(分别使用malloc[[XX alloc] init]),您可以将对象的所有权转移出ARC,并使用(__bridge_retained void *) 转换将其存储在st->arg 中。

要使用对象,请使用(__bridge NSObject *) 进行转换。这不会改变所有权。

当您准备好释放对象时,通过使用(__bridge_transfer NSObject *) 进行强制转换,将所有权传回给 ARC。然后您可以将void * 指针设置为NULL

总体来说是这样的:

struct st_type {
    void *arg; 
};

void init()
{
    NSObject *obj = [[NSObject alloc] init];
    struct st_type *st = malloc(sizeof(struct st_type));
    // transfer ownership out of ARC
    st->arg = (__bridge_retained void *)obj;
}

void use_struct(struct st_type *st){
    // no change in ownership
    NSObject *obj = (__bridge NSObject *)st->arg;
    // use `obj`
}

void release_object(struct st_type *st){
    // transfer ownership back to ARC
    NSObject *obj = (__bridge_transfer NSObject *)st->arg;
    st->arg = NULL;
}

【讨论】:

  • 虽然这不是异常的关键原因,但我认为这是使用bridge的最佳实践。谢谢。
猜你喜欢
  • 2011-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多