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

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

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

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

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

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

2 ответа

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

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

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

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

Другие вопросы по тегам