2012-01-23 3 views
12

Я пишу небольшую библиотеку, которая принимает указатель FILE * как входной.Должна ли моя библиотека обрабатывать SIGSEGV на вводе неправильного указателя?

Если я сразу же проверю этот указатель FILE * и найду, что он ведет к segfault, правильнее ли обрабатывать сигнал, устанавливать errno и изящно выйти; или ничего не делать и использовать обработчик обработчика вызывающего абонента, если он есть?

Преобладающая мудрость, кажется, «библиотеки никогда не должны вызывать аварии». Но я думаю, что, поскольку этот конкретный сигнал, безусловно, является ошибкой вызывающего, тогда я не должен пытаться скрывать эту информацию от него. У него может быть установлен собственный обработчик, чтобы реагировать на проблему по-своему. Та же самая информация может быть получена с помощью errno, но назначение по умолчанию для SIGSEGV было установлено по уважительной причине, и передача сигнала подтверждает эту философию либо заставляя вызывающего абонента обрабатывать его ошибки, либо путем сбоя и защиты от дальнейшего повреждения ,

Вы согласны с этим анализом или вы видите какую-то вескую причину для обращения к SIGSEGV в этой ситуации?

+2

AFAIK standard C library не справляется с сбоем внутри, почему ваш lib должен? Однако я предполагаю, что это зависит от того, что вы планируете делать с вашей библиотекой. (Как проверка на FILE * приводит к SIGSEV btw? Просто любопытно) – BigMike

ответ

7

Взятие обработчиков не является библиотечным бизнесом, я бы сказал, что это несколько оскорбительно из них, если явно не просить. Для минимизации сбоев библиотека может в некоторой степени проверить их ввод. Помимо этого: мусор в мусоре.

+0

+1 за то, что он оскорбителен –

5

Преобладающая мудрость, кажется, «библиотеки никогда не должны вызывать аварии».

Я не знаю, откуда вы это взяли, - если они передают неверный указатель, вы должны потерпеть крах. Любая библиотека будет.

+0

Интересно, что, хотя ваше утверждение верно для большинства функций, есть некоторые исключения. Например, write и getline выйдут с EBADF и EINVAL, соответственно. – User123abc

+0

Извините, это EFAULT для записи, хотя он также делает чек для EBADF. – User123abc

+0

@ User123abc, вы уверены, что говорите о каком-либо недействительном указателе, а не о нулевом указателе? –

2

Это субъективный вопрос, и, возможно, не подходит для SO, но я представлю свое мнение:

Подумайте об этом так: Если у вас есть функция, которая принимает NUL завершающего char * строки и документированную как таковой, и вызывающий передает строку без терминатора nul, вы должны поймать сигнал и пощекотать вызывающего абонента на запястье? Или вы можете позволить ему сбой и заставить плохого программиста использовать ваш API для исправления его/ее кода?

Если ваш код принимает FILE * указатель, а ваша документация говорит «пройти любой открытый FILE *», и они проходят закрытым или признаны недействительными FILE * объекта, они нарушили договор. Проверка этого случая замедлит код людей, которые должным образом используют вашу библиотеку для размещения людей, которые этого не делают, в то время как разрешение аварии будет поддерживать код как можно быстрее для людей, которые читают документацию и пишут хороший код.

Ожидает ли кто-нибудь, кто передает недействительный указатель FILE *, чтобы проверить и правильно обработать ошибку? Или они более склонны слепо продолжать, вызывая еще один крах позже, и в этом случае обработка этого сбоя может просто замаскировать ошибку?

+1

Далее нет причин ожидать, что даже можно поймать случай передачи недопустимого 'ФАЙЛА *'. Это полностью зависит от реализации системы и внутреннего поведения. Недопустимый «ФАЙЛ *» может легко «работать», но сделать что-то совершенно поддельное, даже испортить ваш библиотечный код и не допустить его проверки (в системе без защиты памяти). –

3

Я счел бы разумным проверить специальный случай указателя NULL. Но помимо этого, если они передают барахло, они нарушили контракт с функцией, и они получили сбой.

1

Ядра не должны падать, если вы кормите их плохой указатель, но библиотеки, вероятно, должны. Это не означает, что вы не должны проверять ошибки; хорошая программа немедленно умирает перед лицом необоснованно плохих данных. Я бы предпочел залог библиотеки с assert (f! = NULL), чем просто переходить и в конечном итоге разыменовать указатель NULL.

0

Извините, но люди, которые говорят, что библиотека должна потерпеть крах, просто ленивы (возможно, время рассмотрения, а также усилия по развитию). Библиотеки - это коллекции функций. Библиотечный код не должен «просто терпеть крах» больше, чем другие функции вашего программного обеспечения должны «просто сбой».

Конечно, библиотеки могут иметь некоторые проблемы вокруг как пройти ошибки через границу API, если бы обычно участвуют несколько языков или (относительно) особенности экзотических языков, как исключения, но нет ничего TOO особенного. Действительно, это всего лишь часть бремени написания библиотек, а не кода приложения.

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

Есть несколько способов справиться с этим, что вы, вероятно, должны делать, в порядке предпочтения, является одним из:

  1. Используйте язык, который поддерживает исключения (или лучше, дизайн по контракту) внутри библиотек, а также исключить или разрешить заключение контракта.

  2. Предоставить сигнал обработки ошибок/слот или механизм крюка/обратного вызова и вызвать любые зарегистрированные обработчики. Требовать, чтобы, когда ваша библиотека инициализирована, регистрируется хотя бы один обработчик ошибок.

  3. Поддержка возврата некоторого кода ошибки в каждую функцию, которая по какой-либо причине может выйти из строя. Но это старый, относительно безумный способ делать вещи из C (в отличие от C++) дней.

  4. Установите некоторый глобальный «флаг с ошибкой» и разрешите очистить этот флаг перед вызовами. Это также старый, и полностью безумный, в основном потому, что он перемещает нагрузку на статус ошибки для вызывающего, и небезопасно, когда дело доходит до потоковой передачи.

Смежные вопросы