longjmp и RAII

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

static jmp_buf abort_buffer;
static void abort_handler(int) {
    longjmp(abort_buffer, 1); // perhaps siglongjmp if available..
}

int function(int x, int y) {

    struct sigaction new_sa;
    struct sigaction old_sa;

    sigemptyset(&new_sa.sa_mask);
    new_sa.sa_handler = abort_handler;
    sigaction(SIGABRT, &new_sa, &old_sa);

    if(setjmp(abort_buffer)) {
        sigaction(SIGABRT, &old_sa, 0);
        return -1
    }

    // attempt to do some work here
    int result = f(x, y); // may call abort!

    sigaction(SIGABRT, &old_sa, 0);
    return result;
}

Не очень элегантный код. Поскольку этот шаблон приходится повторять в нескольких местах кода, я хотел бы немного упростить его и, возможно, обернуть его в объект многократного использования. Моя первая попытка связана с использованием RAII для обработки настройки / удаления обработчика сигнала (это необходимо сделать, потому что каждая функция требует разной обработки ошибок). Итак, я придумал следующее:

template <int N>
struct signal_guard {
    signal_guard(void (*f)(int)) {
        sigemptyset(&new_sa.sa_mask);
        new_sa.sa_handler = f;
        sigaction(N, &new_sa, &old_sa);
    }

    ~signal_guard() {
        sigaction(N, &old_sa, 0);
    }
private:
    struct sigaction new_sa;
    struct sigaction old_sa;
};


static jmp_buf abort_buffer;
static void abort_handler(int) {
    longjmp(abort_buffer, 1);
}

int function(int x, int y) {
    signal_guard<SIGABRT> sig_guard(abort_handler);

    if(setjmp(abort_buffer)) {
        return -1;
    }

    return f(x, y);
}

Конечно, тело функции намного проще и понятнее, но сегодня утром у меня возникла мысль. Это гарантированно сработает? Вот мои мысли:

  1. Никакие переменные не являются изменчивыми или изменяются между вызовами setjmp / longjmp .
  2. Я нахожусь longjmp в том же фрейме стека, что и setjmp и return , как обычно, поэтому я разрешаю коду выполнить код очистки, который компилятор выдал в точках выхода функции.
  3. Похоже, он работает должным образом.

Но я все еще чувствую, что это, скорее всего, неопределенное поведение. Как вы думаете, ребята?

10
задан skaffman 29 March 2011 в 09:08
поделиться