Я хочу сделать что-то более полезное с assert
чем просто abort
Это включает в себя сброс некоторых открытых файлов и печать трассировки стека.
Я прочитал несколько статей об утверждении, таких как Утверждения Андрея Александреску который говорит о том, как реализовать утверждения. Однако я хочу заменить обработчик assert своим собственным даже в сторонних библиотеках которые используются моей программой. Я понимаю большинство (но не все) компиляторы (gcc, MSVC, clang) & У библиотек (Qt, boost), которые я использую, есть опции, чтобы установить пользовательский обработчик assert. Однако в настоящее время мне не интересно иметь Abort,Retry,Ignore
особенность для assert, и поэтому не глядя на мой код в специфичном для компилятора / библиотеки обработчике assert.
Насколько я понимаю, assert
звонки abort
который отправляет SIGABRT
сигнал, могу ли я перехватить этот сигнал и выполнить полезные задачи?
Как насчет угона assert()
с вашей собственной реализацией? В системах Unix вы можете использовать Трюк LD_PRELOAD угнать __assert_fail
(assert()
сам по себе это просто макрос, который вызывает более поздний).
Другая возможность — захватить SIGABRT, как вы предлагаете. Однако я вижу несколько требований:
Способ отличить вызов assert()
от других возможных причин получения SIGABRT. Это может быть вызов kill()
из другого потока или процесса, или даже вызов abort()
сам из проверки работоспособности функций управления кучей (free()
, malloc()
…). Это может быть сделано обработчиком сигнала ABRT путем проверки стека выполнения процесса или контекста, переданного в sigaction()
в некоторых системах (этот параметр void * никто не знает, как использовать).
Если вы решили захватить SIGABRT, вы должны иметь в виду, что обработчики сигналов не «легально» могут делать много (даже не вызов printf), что делает их плохими кандидатами на «что-то более полезное», как вы просите.
Так что было бы лучше иметь выделенную ветку, постоянно ожидающую
для сигнала с sigwait()
(основываясь на том, как abort()
является
реализовано это может быть не вариант) или уведомлено сигналом
обработчик всякий раз, когда сигнал принят, что он может сделать основную часть
работа вне контекста обработчика сигнала.
Также важно отметить, что если в своей реализации SIGABRT отправляется abort()
в частности, к вызывающему потоку его прием будет синхронным, и вы можете вызывать асинхронные небезопасные функции.
Собирая сигнал самостоятельно и изменяя маску сигналов потоков, вы можете повлиять на поведение сигнала: эти сторонние библиотеки Вы упоминаете (они могли бы захватывать SIGABRT сами).
Даже если вы захватите SIGABRT с помощью своего собственного обработчика сигнала, вы не сможете вернуться к нормальному выполнению, сигнал был отправлен из вызова в abort()
потому что (цитата из тревоги (8)):
Если SIGABRT сигнал игнорируется или перехватывается обработчиком, который возвращает,
прервать () функция все равно прекратит процесс. Оно делает
это путем восстановления расположения по умолчанию для SIGABRT и затем повышение сигнала во второй раз.
Других решений пока нет …