Ошибка проверки fprintf при печати в stderr - PullRequest
9 голосов
/ 31 января 2011

Согласно документации, fprintf может потерпеть неудачу и при неудаче выдаст отрицательное число.Очевидно, что во многих случаях было бы полезно проверить это значение.

Однако я обычно использую fprintf для вывода сообщений об ошибках в stderr.Мой код обычно будет выглядеть примерно так:

rc = foo();
if(rc) {
  fprintf(stderr, "An error occured\n");
  //Sometimes stuff will need to be cleaned up here
  return 1;
}

В этих случаях возможен ли сбой fprintf?Если да, то можно ли что-то сделать для отображения сообщения об ошибке или есть более надежная альтернатива fprintf?

Если нет, нужно ли проверять fprintf, когда он используется таким образом?

Ответы [ 5 ]

12 голосов
/ 31 января 2011

Стандарт C говорит, что файловые потоки stdin, stdout и stderr должны быть где-то соединены, но они, конечно, не указывают где.Вполне возможно запустить программу с перенаправленным ими:

some_program_of_yours >/dev/null 2>&1 </dev/null

Ваши записи будут успешными, но информация никуда не денется.Более жестокий способ запуска вашей программы:

some_program_of_yours >&- 2>&- </dev/null

На этот раз она была запущена без открытых файловых потоков для stdout и stderr - в нарушение стандарта.В этом примере он все еще читает из / dev / null, что означает, что он не получает никаких полезных данных от stdin.

Многие программы не удосуживаются проверить, что стандартные каналы ввода / выводаоткрыть.Многие программы не заботятся о том, чтобы сообщение об ошибке было успешно написано.Разработка подходящего запасного варианта в виде набросков Tim Post и whitey04 не всегда стоит усилий.Если вы запустите команду ls с подавленными выходными данными, она просто сделает все возможное и завершит работу с ненулевым статусом:

$ ls; echo $?
gls
0
$ ls >&- 2>&-; echo $?
2
$

(проверено RHEL Linux.)нужно для этого делать больше.С другой стороны, если ваша программа должна работать в фоновом режиме и записывать в файл журнала, она, вероятно, не будет много писать в stderr, если она не сможет открыть файл журнала (или не обнаружит ошибку в файле журнала).

Обратите внимание, что если вы вернетесь к syslog(3) (или POSIX ), у вас нет возможности узнать, были ли ваши вызовы «успешными» или нет;все функции системного журнала не возвращают информацию о состоянии.Вы просто должны предположить, что они были успешными.Поэтому это ваше последнее средство.

9 голосов
/ 31 января 2011

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

У вас есть несколько вариантов:

  • Если fprintf завершается неудачно, попробуйте syslog.
  • Если оба не удаются, попробуйте создать файл 'crash. {Pid} .log', который содержитинформация, которую вы хотели бы в отчете об ошибке.При запуске проверьте наличие этих файлов, так как они могут сообщить вашей программе, что она аварийно завершилась ранее.
  • Позвольте пользователям, подключенным к сети, проверить параметр конфигурации, позволяющий вашей программе отправить отчет об ошибке.

Кстати, open() read() и write() - хорошие друзья, когда семейство функций fprintf не работает.

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

Например:

    best_effort_logger(LOG_CRIT, "Heap corruption likely, bailing out!");

Гораздо чище, чем серия if else else if в каждом местечто-то может пойти не так.

4 голосов
/ 31 января 2011

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

Ключ в том, что ваше приложение "изящно" обрабатываетэто (например, ОС не должна убивать ее за то, что она плохая, и она говорит вам, почему она вышла [если она может]).

3 голосов
/ 31 января 2011

Да, конечно, от fprintf до stderr может произойти сбой. Например, stderr может быть обычным файлом, и на диске может не хватить места, или это может быть канал, который закрывается читателем и т. Д.

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

2 голосов
/ 31 января 2011

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

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