Подтвердить что ты не робот

Должна ли моя библиотека обрабатывать SIGSEGV при вводе неправильного указателя?

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

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

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

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

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

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