int sigaltstack(const stack_t *ss, stack_t *oss);
glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
sigaltstack():
代替シグナルスタックを使う際の一般的な手順は、以下の通りである:
ss 引き数は、新しいシグナルスタックを指定するために使う。 また oss 引き数は、現在確立されている シグナルスタックの情報を取得するために使う。 この操作のうち 1 つだけを実行させるには、 使用しない引き数を NULL に指定すればよい。 引き数となる構造体は、以下のような型である:
typedef struct { void *ss_sp; /* スタックのベースアドレス */ int ss_flags; /* フラグ */ size_t ss_size; /* スタックのバイト数 */ } stack_t;
新規の代替シグナルスタックを確立するには、 ss.ss_flags を 0 に設定し、 ss.ss_sp と ss.ss_size に スタックの開始アドレスとスタックサイズを指定する。 定数 SIGSTKSZ は、代替シグナルスタックが通常必要する サイズよりも充分大きく定義されている。 また定数 MINSIGSTKSZ は、 シグナルハンドラーの実行に必要な最小サイズに定義されている。
代替スタックでシグナルハンドラーが起動された場合には、 カーネルにより自動的に、ss.ss_sp で指定されたアドレスは 動作しているハードウェアアーキテクチャーに適したアドレス境界に 調整される。
既存のスタックを無効にするには、 ss.ss_flags を SS_DISABLE に指定する。 この場合、ss の他のフィールドは無視される。
oss が NULL 以外の場合、 oss に代替シグナルスタックの情報が返される。 これは (実質的に) sigaltstack() の呼び出しより先に行われる。 oss.ss_sp と oss.ss_size フィールドに スタックの開始アドレスとスタックサイズが返される。 oss.ss_flags には以下のどちらかの値が返される:
プロセスが標準のシグナルスタックを使い果たすことが予想される場合は、 代替シグナルスタックを確立すると便利である。 例えば、スタックが最上位アドレスから 下位アドレス方向に非常にたくさん積まれてしまうことで、 最下位アドレスから上位アドレス方向に積まれるヒープとぶつかってしまう場合や、 setrlimit(RLIMIT_STACK, &rlim) の呼び出しで確立された 制限に達してしまった場合に、この様な事が起こる。 標準のスタックを使い果たしてしまうと、 カーネルはプロセスに SIGSEGV シグナルを送る。 このような状況では、代替シグナルスタック上でしかシグナルをキャッチできない。
Linux がサポートする多くのハードウェアアーキテクチャーでは、 スタックは下位アドレス方向に積まれる。 sigaltstack() はスタックが積まれる方向を自動的に決定する。
代替シグナルスタック上で実行されている シグナルハンドラーから呼ばれる関数も、代替シグナルハンドラーを使う (プロセスが代替シグナルスタック上で実行されている場合、 他のシグナルで呼び出されるハンドラーもこの代替シグナルハンドラーを使う)。 標準のスタックとは異なり、 システムは代替シグナルスタックを自動的に拡張しない。 代替シグナルスタック用に確保したサイズを越えた場合、 結果は予想できない。
execve(2) の呼び出しが成功すると、 既存の全ての代替シグナルスタックが削除される。 fork(2) 経由で作成された子プロセスは、親プロセスの代替シグナルスタックの 設定のコピーを継承する。
sigaltstack() は以前の sigstack() を置き換えるものである。 過去プログラムとの互換性のため、glibc では sigstack() も提供している。 新しいのアプリケーションは全て sigaltstack() を使って書くべきである。
stack_t ss; ss.ss_sp = malloc(SIGSTKSZ); if (ss.ss_sp == NULL) /* ハンドルエラー */; ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) == -1) /* ハンドルエラー */;