Обнаружение рекурсии устойчиво даже при наличии нелокальных прыжков

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

Обычно я просто пишу что-то вроде

void foo() {
    static int recursed = 0;
    if(recursed) {
        ...
    }
    recursed = 1;
    othercode();
    recursed = 0;
}

но в этом случае я обеспокоен тем, что othercode может использовать longjmp или аналогичный для разрыва, в результате чего recursed остается в 1. В случае, если моя функция выскочила из этого, Я хочу убедиться, что он не считает себя рекурсивным, если он вызван позже (тот факт, что это longjmp 'd out, не является проблемой в противном случае).

Примечание. Я считаю longjmp вероятным. othercode является цепным сигнальным обработчиком из какого-либо другого кода в-диком, и существуют, например, обработчики, например. SIGSEGV, которые используют longjmp для восстановления контекста (например, как обработчики исключений "защита от ошибок" ). Обратите внимание, что использование longjmp в синхронном обработчике сигналов, как правило, безопасно. В любом случае, я не особо забочусь о том, безопасен ли другой код вообще, потому что это не то, что под моим контролем.

Ответ 1

Не уверен, какой именно код будет выглядеть для этого, но вместо статического int вы можете иметь статический void *. Вместо того, чтобы устанавливать его в 1, установите его для указания на текущий стек стека. В дополнение к проверке, если это отличное от нуля, вы проверяете, чтобы обратный адрес из следующего стека стека после recursed фактически указывал на местоположение в коде foo, а также что recursed находится выше текущего указателя стека, т.е. не выскочил.

Звучит очень хрупко и зависит от архитектуры.

Ответ 2

В соответствии со стандартом POSIX для signal (7) longjmp() не является одним из вызовов, безопасных для вызова изнутри обработчик сигнала. Прежде чем даже подумать об этом, в документации longjmp (3) вам нужно убедиться, что код, который вы вызываете, использует sigsetjmp() и siglongjmp ( )

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