奇怪的 KERN_INVALID_ADDRESS 异常?
weird KERN_INVALID_ADDRESS exception?
我遇到了一个奇怪的 OC 异常,看起来我正在向已释放的地址发送消息,但是当我
- 尝试检查它是否为 NULL,它仍然崩溃。
- 尝试调试或添加@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 *
。例如,这与作为回调传递给工作表的 old-style context
或 userInfo
指针类似。
参见 ARC: __bridge versus __bridge_retained using contextInfo test case for an example. I also assume you're using ARC (please read Casting and Object Lifetime Semantics)。
假设结构的生命周期比 Objective-C 对象的生命周期长,并且您明确地在结构中设置和释放对象,那么您不需要字典来进行内存管理。
分配结构和对象后(分别使用 malloc
和 [[XX alloc] init]
),您可以将对象的所有权转移出 ARC 并使用 st->arg
将其存储在 st->arg
中=17=]投.
要使用该对象,请使用 (__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;
}
我遇到了一个奇怪的 OC 异常,看起来我正在向已释放的地址发送消息,但是当我
- 尝试检查它是否为 NULL,它仍然崩溃。
- 尝试调试或添加@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 *
。例如,这与作为回调传递给工作表的 old-style context
或 userInfo
指针类似。
参见 ARC: __bridge versus __bridge_retained using contextInfo test case for an example. I also assume you're using ARC (please read Casting and Object Lifetime Semantics)。
假设结构的生命周期比 Objective-C 对象的生命周期长,并且您明确地在结构中设置和释放对象,那么您不需要字典来进行内存管理。
分配结构和对象后(分别使用 malloc
和 [[XX alloc] init]
),您可以将对象的所有权转移出 ARC 并使用 st->arg
将其存储在 st->arg
中=17=]投.
要使用该对象,请使用 (__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;
}