处理和报告Objective-C中整数溢出导致的内存分配错误的最佳方法?

处理和报告Objective-C中整数溢出导致的内存分配错误的最佳方法?,objective-c,memory-management,error-reporting,integer-overflow,Objective C,Memory Management,Error Reporting,Integer Overflow,首先,我要说的是,我理解我所描述的问题是如何以及为什么会发生的。我是计算机科学专业的学生,我理解溢出/下溢和有符号/无符号算术。(对于不熟悉该主题的人,请简要阅读苹果的安全编码指南。) 我的问题是,一旦检测到错误,就报告并从中恢复,更具体地说,在Objective-C框架的情况下。(我编写并维护)我有几个collections类,它们为存储对象分配内存,并根据需要动态扩展。我还没有看到任何与溢出相关的崩溃,可能是因为我的测试用例大多使用正常的数据。然而,考虑到未经验证的值,事情可能会很快爆发,我

首先,我要说的是,我理解我所描述的问题是如何以及为什么会发生的。我是计算机科学专业的学生,我理解溢出/下溢和有符号/无符号算术。(对于不熟悉该主题的人,请简要阅读苹果的安全编码指南。)

我的问题是,一旦检测到错误,就报告并从中恢复,更具体地说,在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如果用户的数据已损坏,请尽量不要保留损坏的数据,并让用户知道出现了严重错误