Должна ли моя библиотека обрабатывать SIGSEGV при неправильном вводе указателя? - PullRequest
12 голосов
/ 23 января 2012

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

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

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

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

Ответы [ 6 ]

7 голосов
/ 23 января 2012

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

5 голосов
/ 23 января 2012

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

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

3 голосов
/ 23 января 2012

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

2 голосов
/ 23 января 2012

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

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

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

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

1 голос
/ 23 января 2012

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

0 голосов
/ 23 февраля 2013

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

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

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...