SIGALTSTACK(2)

ИМЯ
sigaltstack - считывает или устанавливает расположение стека сигналов

ОБЗОР
#include <signal.h>

int sigaltstack(const stack_t *ss, stack_t *old_ss);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

sigaltstack():
    _XOPEN_SOURCE >= 500
        || /* начиная с glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
        || /* в версии glibc <= 2.19: */ _BSD_SOURCE

ОПИСАНИЕ
Вызов sigaltstack() позволяет процессу определить новый альтернативный стек сигналов и/или получить состояние уже имеющегося альтернативного стека сигналов. Альтернативный стек сигналов используется при выполнении обработчика сигналов, если он был запрошен при установлении обработчика (см. sigaction(2)).

Обычный порядок действий для использования альтернативного стека сигналов:

1.  Выделить область памяти, которая будет использована под альтернативный стек сигналов.

2.  Вызвать sigaltstack() для информирования системы о существовании и расположении альтернативного стека сигналов.

3.  При установке обработчика сигналов с помощью sigaction(2) (флагом SA_ONSTACK) сообщить системе, что обработчик сигналов должен выполняться с альтернативным стеком сигналов.

Аргумент ss используется для указания нового альтернативного стека сигналов, а аргумент old_ss используется для получения информации об установленном в данный момент стеке сигналов. Если интересует какая-то одна из этих задач, то другой аргумент указывается как NULL.

Тип stack_t, используемый для аргументов этой функции, определён следующим образом:

    typedef struct {
        void  *ss_sp;     /* базовый адрес стека */
        int    ss_flags;  /* флаги */
        size_t ss_size;   /* количество байт в стеке */
    } stack_t;

Для организации нового альтернативного стека сигналов поля этой структуры должны быть заполнены следующим образом:

ss.ss_flags
    В этом поле содержится 0 или следующий флаг:

    SS_AUTODISARM (начиная с Linux 4.7)
        Очистить настройки альтернативного стека сигналов в записи обработчика сигналов. Когда происходит возврат из обработчика сигналов, восстанавливаются предыдущие настройки альтернативного стека сигналов.

        Этот флаг был добавлен для безопасного переключения из обработчика сигналов с помощью swapcontext(3). Без этого флага следующий обрабатываемый сигнал повредит состояние обработчика сигналов, в который выполняется переключение (switched-away). В ядрах без поддержки этого флага вызов sigaltstack() завершается ошибкой EINVAL, если этот флаг указан.

ss.ss_sp
    Это поле задаёт начальный адрес стека. При вызове обработчика сигнала с альтернативным стеком ядро автоматически выравнивает адрес, указанный в ss.ss_sp, по границе адреса, подходящей для используемой аппаратной платформы.

ss.ss_size
    В этом поле задаётся размер стека. Для определения альтернативного стека сигналов достаточного размера можно использовать константу SIGSTKSZ, а для выделения стека минимального размера можно указать константу MINSIGSTKSZ.

Для отключения существующего стека, укажите в ss.ss_flags значение SS_DISABLE. В этом случае ядро игнорирует все флаги в ss.ss_flags и остальные поля в ss.

Если old_ss не равно NULL, то в нём возвращается информация об альтернативном стеке сигналов, который использовался до этого вызова sigaltstack(). В полях old_ss.ss_sp и old_ss.ss_size возвращаются начальный адрес и размер стека. В old_ss.ss_flags может быть возвращено одно из следующих значений:

SS_ONSTACK
    В данный момент альтернативный стек сигналов используется процессом (заметим, что в этот момент невозможно изменить альтернативный стек сигналов).

SS_DISABLE
    В данный момент альтернативный стек сигналов выключен.

    Также это значение возвращается, если процесс уже выполняется с альтернативным стеком сигналов, установленным с помощью флага SS_AUTODISARM. В этом случае с помощью swapcontext(3) можно безопасно переключаться в другой обработчик сигналов. Также возможно установить другой альтернативный стек сигналов с помощью последующего вызова sigaltstack().

SS_AUTODISARM
    Альтернативный стек сигналов был помечен к автоматической очистке (autodisarmed), как описывалось ранее.

Если присвоить ss значение NULL,а old_ss — не NULL, то можно получить текущие настройки альтернативного стека сигналов без его изменения.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении sigaltstack() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

EFAULT
    Значение ss или old_ss не равно NULL и указывает за пределы адресного пространства процесса.

EINVAL
    Значение ss не равно NULL и в поле ss_flags содержится некорректный флаг.

ENOMEM
    Указанный размер нового альтернативного стека сигналов ss.ss_size меньше MINSIGSTKSZ.

EPERM
    Была попытка изменить альтернативный стек сигналов при его активности (т. е. текущий альтернативный стек сигналов уже задействован при выполнении процесса).

АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение
sigaltstack() | Безвредность в нитях | MT-Safe

СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SUSv2, SVr4.

Флаг SS_AUTODISARM является расширением Linux.

ЗАМЕЧАНИЯ
В основном, альтернативный стек сигналов используется при обработке сигнала SIGSEGV, который возникает при нехватке свободного места в обычном стеке процесса: в этом случае обработчик сигнала SIGSEGV не может использовать стек процесса; если требуется обработка данного сигнала, нужно использовать альтернативный стек сигналов.

Назначение альтернативного стека сигналов полезно, если ожидается, что процесс может задействовать весь свой обычный стек. Это может случиться, например, когда стек становится настолько большим, что он встречается с растущей в вверх «кучей», или достигает ограничения, заданного вызовом setrlimit(RLIMIT_STACK, &rlim). Если стандартный стек закончился, то ядро посылает процессу сигнал SIGSEGV. В этих условиях единственным способом поймать сигнал будет задействование альтернативного стека сигналов.

На большинстве аппаратных архитектур, поддерживаемых Linux, стеки растут сверху вниз. Вызов sigaltstack() автоматически учтёт направление роста стека.

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

При успешном выполнении вызова execve(2) любой существующий альтернативный стек сигналов удаляется. Дочерний процесс, созданный с помощью fork(2), наследует копию настроек альтернативного стека сигналов своего родителя.

Вызов sigaltstack() заменяет устаревший вызов sigstack(). Для обратной совместимости в glibc также есть функция sigstack(). Во всех новых приложениях нужно использовать sigaltstack().

  История
Системный вызов sigstack() появился в 4.2BSD. В нём использовалась слегка другая структура, и его главным недостатком было то, что вызывающий должен был учитывать направления роста стека.

ПРИМЕР
В следующем сегменте кода показано использование sigaltstack() (и sigaction(2)) для установки альтернативного стека сигналов, который используется обработчиком для сигнала SIGSEGV:

    stack_t ss;
    ss.ss_sp = malloc(SIGSTKSZ);
    if (ss.ss_sp == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    ss.ss_size = SIGSTKSZ;
    ss.ss_flags = 0;
    if (sigaltstack(&ss, NULL) == -1) {
        perror("sigaltstack");
        exit(EXIT_FAILURE);
    }
    sa.sa_flags = SA_ONSTACK;
    sa.sa_handler = handler();      /* адрес обработчика сигналов */
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGSEGV, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

ДЕФЕКТЫ
В Linux 2.2 и старее в ss.sa_flags можно указывать только флаг SS_DISABLE. В версиях до ядра Linux 2.4 разрешалось sigaltstack() допускать ss.ss_flags==SS_ONSTACK с тем же смыслом как ss.ss_flags==0 (т. е., при включении SS_ONSTACK в ss.ss_flags ни к чему не приводило). В других реализациях и согласно POSIX.1 флаг SS_ONSTACK появляется в old_ss.ss_flags только как флаг результата. В Linux его не нужно даже указывать в ss.ss_flags, иначе это снизит переносимость, так как некоторые системы выдают ошибку, если в ss.ss_flags указан SS_ONSTACK.

СМОТРИТЕ ТАКЖЕ
execve(2), setrlimit(2), sigaction(2), siglongjmp(3), sigsetjmp(3), signal(7)