Лучший способ обработать и сообщить об ошибках распределения памяти из-за целочисленного переполнения в Objective C?

Для начала позвольте мне сказать, что я понимаю, как и почему проблема, которую я описываю, может произойти. Я был главной Информатикой, и я понимаю переполнение/потерю значимости и арифметику со знаком/неподписанную. (Для незнакомых с темой, Безопасное Руководство по Кодированию Apple обсуждает целочисленное переполнение кратко.)

Мой вопрос о создании отчетов и восстановлении с такой ошибки, после того как это было обнаружено, и более конкретно в случае платформы Objective C. (Я пишу и поддерживаю CHDataStructures.) У меня есть несколько классов наборов, которые выделяют память для того, чтобы хранить объекты и динамично расширяются по мере необходимости. Я еще не видел связанных с переполнением катастрофических отказов, вероятно, потому что мои тестовые сценарии главным образом используют нормальные данные. Однако, учитывая непроверенные значения, вещи могли взорваться скорее быстро, и я хочу предотвратить это.

Я определил по крайней мере два общих падежа, где это может произойти:

  1. Вызывающая сторона передает очень большое неподписанное значение (или отрицательное значение со знаком) к -initWithCapacity:.
  2. Достаточно объектов было добавлено для порождения возможности динамично расшириться, и способность стала достаточно большой для порождения переполнения.

Легкая часть обнаруживает, произойдет ли переполнение. (Например, прежде, чем попытаться выделить length * sizeof(void*) байты, я могу проверить ли length <= UINT_MAX / sizeof(void*), так как в случае неудачи тест будет означать, что продукт переполнит и потенциально выделит намного меньший регион памяти, чем желаемый. На платформах, которые поддерживают его, checkint.h API является другой альтернативой.) Более твердая часть определяет, как иметь дело с нею корректно. В первом сценарии вызывающая сторона, возможно, лучше снабжена (или по крайней мере в мышлении) для контакта с отказом. Второй сценарий может произойти где угодно в коде, что объект добавляется к набору, который может быть довольно недетерминирован.

Мой вопрос, затем, является этим: Как код Objective C "добропорядочного гражданина", как ожидают, будет действовать, когда целочисленное переполнение произойдет в этом типе ситуации? (Идеально, так как мой проект является платформой в том же духе как Основа в Какао, я хотел бы смоделировать прочь способа, которым это ведет себя для максимального "согласования полных сопротивлений". Документация Apple, которую я нашел, не упоминает много вообще об этом.) Я полагаю, что в любом случае, сообщая об ошибке данный. Так как API для добавления объекта (который мог вызвать сценарий 2) не принимают параметр ошибок, что я могу действительно сделать, чтобы помочь разрешить проблему, если что-нибудь? Что действительно рассматривают хорошо в таких ситуациях? Я не испытываю желания сознательно писать склонный к катастрофическому отказу код, если я могу добиться большего успеха...

9
задан Quinn Taylor 7 March 2010 в 06:19
поделиться

5 ответов

Здесь есть две проблемы :

(1) Выделение не удалось, и вам не хватает памяти.

(2) Вы обнаружили переполнение или другое ошибочное состояние, которое приведет к (1), если вы продолжите.

В случае (1) вы попали в ловушку (если только неудавшееся выделение было слишком большим и вы знаете , что неудачное выделение было только этим). Если это произойдет, лучшее, что вы можете сделать, - это разбиться как можно быстрее и оставить как можно больше улик. В частности, создание функции, которая вызывает abort () с именем вроде IAmCrashingOnPurposeBecauseYourMemoryIsDepleted () , оставит свидетельства в журнале сбоев.

Если это действительно так (2), то возникают дополнительные вопросы. В частности, можете ли вы выйти из ситуации и, независимо от того, остались ли данные пользователя нетронутыми? Если вы можете выздороветь, тогда здорово ... сделайте это, и пользователь никогда не узнает. Если нет, то вы должны быть абсолютно уверены, что данные пользователя не повреждены . Если это не так, спасайтесь и умрите. Если данные пользователя повреждены, сделайте все возможное, чтобы не сохранять поврежденные данные и сообщить пользователю, что что-то пошло не так. Если данные пользователя уже сохранены, но повреждены, то ... ну ... ой ... вы можете подумать о создании какого-либо инструмента восстановления.

3
ответ дан 4 December 2019 в 20:23
поделиться

Что касается динамически растущего хранилища на основе массивов, здесь можно сделать очень много. Я разработчик планировщика Moab для суперкомпьютеров, и мы также имеем дело с очень большим количеством систем с тысячами процессоров, тысячами заданий и огромными объемами вывода заданий. В какой-то момент вы не можете объявить буфер больше, не создавая совершенно новый тип данных для работы с размерами, превышающими UINT_MAX или LONG_LONG_MAX и т. Д., И в этот момент на большинстве «обычных» машин вы будете в любом случае не хватает места в стеке / куче. Поэтому я бы сказал, что записывать значимое сообщение об ошибке, не допускать взрыва коллекции, и если пользователю нужно добавить столько вещей в коллекцию CHDataStructures, они должны знать, что есть проблемы, связанные с очень большими числами, и вызывающий следует проверить, было ли добавление успешным (отслеживать размер коллекции и т. д.).

Другой возможностью является преобразование хранилища на основе массива в хранилище на основе динамически выделяемого связанного списка, когда вы доходите до точки, когда вы не можете выделить больший массив с unsigned int или unsigned long. Это было бы дорого, но происходило бы достаточно редко, чтобы не было ужасно заметно для пользователей фреймворка.Поскольку ограничение на размер динамически выделяемой коллекции на основе связанного списка - это размер кучи, у любого пользователя, добавившего достаточно элементов в коллекцию для «переполнения», возникнут более серьезные проблемы, чем то, был ли его элемент успешно добавлен.

3
ответ дан 4 December 2019 в 20:23
поделиться

Я бы сказал, что правильнее всего было бы делать то, что делают коллекции Какао. Например, если у меня есть следующий код:

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;
}

.. и я просто позволю ему работать, он в конечном итоге умрет с EXC_BAD_ACCESS. (Я скомпилировал и запустил это как 32-битное приложение, чтобы быть уверенным, что у меня закончится место, когда я попаду на 2 ** 32 объекта.

Другими словами, было бы неплохо генерировать исключение, но я не думаю, вам действительно нужно что-то делать.

1
ответ дан 4 December 2019 в 20:23
поделиться

Регистрировать и вызывать исключение.

Вы можете быть хорошим гражданином только для других программистов, а не для конечного пользователя, поэтому передайте проблему наверх и сделайте это таким образом, чтобы четко объяснить, что происходит, в чем проблема (укажите числа) и где она происходит, поэтому первопричину можно устранить.

4
ответ дан 4 December 2019 в 20:23
поделиться

Использование утверждений и пользовательского обработчика утверждений может быть для вас наилучшим вариантом.

С помощью утверждений вы легко можете иметь много контрольных точек в своем коде, где вы проверяете, что все работает так, как должно. В противном случае макрос утверждения по умолчанию регистрирует ошибку (определенную разработчиком строку) и выдает исключение. Вы также можете переопределить поведение по умолчанию с помощью настраиваемого обработчика утверждений и реализовать другой способ обработки условий ошибки (даже избегая создания исключений).

Этот подход обеспечивает большую гибкость, и вы можете легко изменить свою стратегию обработки ошибок (создание исключений или внутреннее устранение ошибок) в любой момент.

Документация очень краткая: Утверждения и ведение журнала .

0
ответ дан 4 December 2019 в 20:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: