Iphone 取消引用NSCoder返回的指针时在iOS设备上崩溃';这是比特索基
在使用Apple LLVM编译器3.0并使用-O3编译时,我发现NSCoder有一个不寻常的崩溃。它只在设备上崩溃。我测试了一台运行iOS 5的iPhone4、一台运行iOS 5的iPad2和一台运行iOS 4的iPad1。所有碰撞相同。以下是代码的相关部分:Iphone 取消引用NSCoder返回的指针时在iOS设备上崩溃';这是比特索基,iphone,xcode,arm,llvm,nscoder,Iphone,Xcode,Arm,Llvm,Nscoder,在使用Apple LLVM编译器3.0并使用-O3编译时,我发现NSCoder有一个不寻常的崩溃。它只在设备上崩溃。我测试了一台运行iOS 5的iPhone4、一台运行iOS 5的iPad2和一台运行iOS 4的iPad1。所有碰撞相同。以下是代码的相关部分: -(id)initWithCoder:(NSCoder*)decoder { if (![super init]) { return nil; } NSUInteger length =
-(id)initWithCoder:(NSCoder*)decoder
{
if (![super init])
{
return nil;
}
NSUInteger length = 0;
uint8_t* data = (uint8_t*)[decoder decodeBytesForKey:BBKey returnedLength:&length];
m_value = *(BBPointI32*)data;
return self;
}
以下是BBPointI32的含义:
typedef struct
{
NSInteger x;
NSInteger y;
}
BBPointI32;
EXC\u BAD\u访问
在数据被取消引用时发生。这不是空指针问题。如果我附加GDB,我可以看到长度是8,sizeof(BBPointI)也是8,并且数据是正确的
如果我看一下拆卸,碰撞发生在:
ldrd r2, r3, [r0]
看起来不错。r0包含0xb546e,它是数据的地址。当我检查内存时,我可以看到它包含了我期望的数据。对于任何感兴趣的人来说,r2包含72(不确定是什么),r3包含8(很可能是length
)的值
有人能解释一下这个问题吗?您使用的是ARC吗?如果是这样,我认为问题在于编译器可以在decodeBytesForKey:
调用之后自由地释放decoder
(因此释放返回值所指向的缓冲区)
都一样。您可以CFRetain
/CFRelease
您的解码器以延长其生命周期,或者稍后在方法中添加一个[解码器自身]
,以使其保持活动状态,直到该点
我想你也可以通过用\uuuu属性((objc\u精确的生命周期))
注释解码器来解决这个问题,但我对它的理解有些模糊。你的例子留下了很多变量,任何潜在的助手都会质疑。举个例子:如果这个无存档的东西有点怪怎么办?内存管理是否正确
我能够重现您看到的崩溃,并且可以确认它仅在启用-O3时发生,而不是在选择None进行优化时发生。以下是崩溃代码的减少,消除了外部变量,如编码器的内存管理等。注意,下面的代码有意保留所有对象,以消除崩溃与意外过度释放或使用ARC的副作用有关的可能性,如Andy在另一个回答中所建议的:
typedef struct
{
NSInteger x;
NSInteger y;
}
BBPointI32;
- (void) testDecoding
{
NSString* myKey = @"Testing";
// First get an coder with bytes in it
NSMutableData* myData = [[NSMutableData data] retain];
NSKeyedArchiver* myCoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:myData];
BBPointI32 encodedStruct = {1234, 5678};
[myCoder encodeBytes:(const uint8_t *)&encodedStruct length:sizeof(encodedStruct) forKey:myKey];
[myCoder finishEncoding];
// Now decode it
BBPointI32 decodedStruct;
NSUInteger decodedLength = 0;
NSKeyedUnarchiver* myDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:myData];
uint8_t* data = (uint8_t*)[myDecoder decodeBytesForKey:myKey returnedLength:&decodedLength];
decodedStruct = *(BBPointI32*)data;
NSLog(@"Got decoded struct with x = %ld, y = %ld, length = %lu", decodedStruct.x, decodedStruct.y, decodedLength);
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSLog(@"Testing decoding");
[self testDecoding];
}
我认为这是一个更简洁的问题描述,任何想帮忙的人都可以以此作为切入的基础。到目前为止,我的直觉是这是LLVM3.0中的一个优化错误,但也许其他人会对正在发生的事情有更好的理论
您在问题中没有提到的一点,但我在设备崩溃时注意到的是,故障伴随着EXC_ARM_DA_ALIGN错误,这是错误访问异常的原因。我在谷歌上搜索了一篇博客文章,其中似乎暗指了与您在这里看到的相同的症状和可能导致崩溃的原因:
事实上,通过改变上面的行
decodedStruct = *(BBPointI32*)data;
到
崩溃行为似乎得到了缓解,代码的行为符合预期。ldrd需要8字节对齐的地址。*(BBPointI32*)数据习惯用法不安全,因为数据不是8字节对齐的。使用memcpy将字节放入结构中。我找到了这个线程,用谷歌搜索“EXC\u ARM\u DA\u ALIGN”和“EXC\u BAD\u ACCESS”。其他答案对我都没有帮助,因为这个错误是因为一些相对简单的事情而出现的。我曾写道:
theArray = [[NSArray alloc] initWithObjects:@"first", @"second", @"third",
@"fourth", @"fifth", "sixth", nil];
i、 我在一个字符串文本前面漏掉了一个@。将其放回解决了错误。谢谢,这是正确的。该问题与编译器决定使用ldrd
有关。当我将数据
转换为BBPointI32*
时,它假定这意味着指针正确对齐,但事实并非如此。因此,不是:m_值=(BBPointI32)数据;我需要使用:memcpy(&m_值、数据、长度)@生物节律学家。。不仅仅是一个搞笑的推特人:)我也经历了类似的事情。发生在iPad3上,而不是iPad2上!我没有注意到我这边的EXC_ARM_DA_ALIGN,但是是的,这也是我做的改变。谢谢你的帮助。哈哈-我花了两个小时试图找到这个。感谢您发布解决方案。
theArray = [[NSArray alloc] initWithObjects:@"first", @"second", @"third",
@"fourth", @"fifth", "sixth", nil];