处理和报告Objective-C中整数溢出导致的内存分配错误的最佳方法?
首先,我要说的是,我理解我所描述的问题是如何以及为什么会发生的。我是计算机科学专业的学生,我理解溢出/下溢和有符号/无符号算术。(对于不熟悉该主题的人,请简要阅读苹果的安全编码指南。) 我的问题是,一旦检测到错误,就报告并从中恢复,更具体地说,在Objective-C框架的情况下。(我编写并维护)我有几个collections类,它们为存储对象分配内存,并根据需要动态扩展。我还没有看到任何与溢出相关的崩溃,可能是因为我的测试用例大多使用正常的数据。然而,考虑到未经验证的值,事情可能会很快爆发,我想防止这种情况发生 我已经确定了至少两种可能发生这种情况的常见情况:处理和报告Objective-C中整数溢出导致的内存分配错误的最佳方法?,objective-c,memory-management,error-reporting,integer-overflow,Objective C,Memory Management,Error Reporting,Integer Overflow,首先,我要说的是,我理解我所描述的问题是如何以及为什么会发生的。我是计算机科学专业的学生,我理解溢出/下溢和有符号/无符号算术。(对于不熟悉该主题的人,请简要阅读苹果的安全编码指南。) 我的问题是,一旦检测到错误,就报告并从中恢复,更具体地说,在Objective-C框架的情况下。(我编写并维护)我有几个collections类,它们为存储对象分配内存,并根据需要动态扩展。我还没有看到任何与溢出相关的崩溃,可能是因为我的测试用例大多使用正常的数据。然而,考虑到未经验证的值,事情可能会很快爆发,我
-initWithCapacity:
最简单的部分是检测是否会发生溢出。(例如,在尝试分配
length*sizeof(void*)之前)
bytes,我可以检查length关于动态增长的、基于阵列的存储,可以做的事情是否只有那么多。我是超级计算机Moab调度程序的开发人员,我们还可以处理具有数千个处理器、数千个作业和大量作业输出的系统上的大量数据。至少在我看来,如果不创建一个全新的数据类型来处理比UINT_MAX或LONG_LONG_MAX等更大的数据,那么不能将缓冲区声明为更大的,而此时大多数情况下都是“正常的”无论如何,您的堆栈/堆空间都将耗尽。因此,我要说的是,记录一条有意义的错误消息,防止集合爆炸,如果用户需要向CHDataStructures集合添加那么多内容,他们应该知道处理非常大的数目的问题,并且调用方应该检查添加是否成功sful(跟踪收集的大小等)
另一种可能性是,当您无法分配具有无符号int或无符号long的较大数组时,将基于数组的存储转换为动态分配的、基于链表的存储。这将非常昂贵,但很少发生,因此框架的用户不会太在意。因为动态分配的、基于链表的集合的大小限制是堆的大小,任何用户向集合中添加足够多的项以“溢出”该集合将比其项是否成功添加有更大的问题。记录并引发异常
对于其他程序员来说,你只能是一个好公民,而不是最终用户,因此,把问题传递到楼上,并以一种清楚地解释发生了什么,问题是什么的方式来做(给出数字)以及它发生的位置,以便消除根本原因。我认为正确的做法是执行Cocoa集合所做的操作。例如,如果我有以下代码:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray * a = [[NSMutableArray alloc] init];
for (uint32_t i = 0; i < ULONG_MAX; ++i) {
for (uint32_t i = 0; i < 10000000; ++i) {
[a addObject:@"foo"];
}
NSLog(@"%lu rounds of 10,000,000 completed", i+1);
}
[a release];
[pool drain];
return 0;
}
int main(int argc,const char*argv[]{
NSAutoreleasePool*池=[[NSAutoreleasePool alloc]init];
NSMutableArray*a=[[NSMutableArray alloc]init];
对于(uint32_t i=0;i
…只要让它运行,它最终会随着EXC_BAD_访问而消亡。(我编译并运行了一个32位的应用程序,这样当我点击2**32对象时,我就可以确保空间用完了。)
换句话说,抛出异常会很好,但我认为您真的不必做任何事情。使用断言和自定义断言处理程序可能是您的最佳选择
使用断言,您可以在代码中轻松设置许多检查点,在这些检查点中,您可以验证事情是否正常工作。如果没有,默认情况下,断言宏将记录错误(开发人员定义的字符串),并引发异常。您还可以使用自定义断言处理程序覆盖默认行为,并实现不同的方法来处理错误条件(甚至避免引发异常)
这种方法允许更大程度的灵活性,您可以在任何时候轻松修改错误处理策略(抛出异常与内部处理错误)
文档非常简洁:。目前有两个问题:
(1) 分配失败,内存不足
(2) 您已检测到溢出或其他错误情况,如果继续,将导致(1)
在第(1)种情况下,您被套住了(除非失败的分配都是愚蠢的大的&您知道失败的分配只有那一个)。如果发生这种情况,您可以做的最好的事情是尽快崩溃并留下尽可能多的证据。特别是,创建一个调用abort()的函数
的名称,如iamcrashingongpurpose,因为您的内存已耗尽()
将在崩溃日志中留下证据
如果是真的(2),然后还有其他问题。具体来说,你能从这种情况中恢复吗?不管用户的数据是否仍然完整?如果你能恢复,那么grand…这样做,用户永远不必知道。如果不能,那么你需要绝对确保用户的数据没有损坏。。如果没有损坏,那么保存并销毁。I如果用户的数据已损坏,请尽量不要保留损坏的数据,并让用户知道出现了严重错误