SIGALTSTACK - Linux手册页

时间:2019-08-20 17:59:25  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-06-09

名称

sigaltstack-设置和/或获取信号栈上下文

语法

#包括

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版本

说明

sigaltstack()允许进程定义新的备用信号堆栈和/或检索现有备用信号堆栈的状态。如果信号处理程序的建立(请参见sigaction(2))请求,则在信号处理程序执行期间使用备用信号堆栈。

使用备用信号栈的正常事件顺序如下:

1.
分配用于备用信号堆栈的内存区域。
2.
使用sigaltstack()通知系统备用信号堆栈的存在和位置。
3.
使用sigaction(2)建立信号处理程序时,通过指定SA_ONSTACK标志通知系统该信号处理程序应在备用信号堆栈上执行。

ss参数用于指定新的备用信号堆栈,而old_ss参数用于检索有关当前建立的信号堆栈的信息。如果我们只想执行这些任务之一,则可以将另一个参数指定为NULL。

用于键入此函数的参数的stack_t类型定义如下:

typedef struct {
    void  *ss_sp;     /* Base address of stack */
    int    ss_flags;  /* Flags */
    size_t ss_size;   /* Number of bytes in stack */
} stack_t;

为了建立新的备用信号栈,此结构的字段设置如下:

ss.ss_flags
This field contains either 0, or the following flag:
SS_AUTODISARM(since Linux 4.7)
在进入信号处理程序时清除备用信号堆栈设置。信号处理程序返回时,将还原以前的备用信号堆栈设置。
添加此标志是为了确保可以安全地通过swapcontext(3)离开信号处理程序。没有此标志,随后处理的信号将破坏已关闭信号处理程序的状态。在不支持此标志的内核上,提供此标志时,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
如上所述,备用信号栈已标记为自动撤防。

通过将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
尝试在备用信号堆栈处于活动状态时对其进行更改(即,该进程已在当前备用信号堆栈上执行)。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
sigaltstack()Thread safetyMT-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()编写。

History

4.2BSD有一个sigstack()系统调用。它使用略有不同的结构,并具有主要缺点,即调用方必须知道堆栈增长的方向。

BUGS

在Linux 2.2及更低版本中,可以在ss.sa_flags中指定的唯一标志是SS_DISABLE。在Linux 2.4内核发布之前,进行了更改,以允许sigaltstack()允许ss.ss_flags == SS_ONSTACK,其含义与ss.ss_flags == 0相同(即,在ss中包含SS_ONSTACK .ss_flags是无操作)。在其他实现上,根据POSIX.1,SS_ONSTACK仅作为报告的标志出现在old_ss.ss_flags中。在Linux上,根本不需要在ss.ss_flags中指定SS_ONSTACK,实际上应该从可移植性的角度避免这样做:如果在ss.ss_flags中指定SS_ONSTACK,则其他各种系统也会出错。

示例

以下代码段演示了如何使用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();      /* Address of a signal handler */
sigemptyset(&sa.sa_mask);
if (sigaction(SIGSEGV, &sa, NULL) == -1) {
    perror("sigaction");
    exit(EXIT_FAILURE);
}

另外参见

execve(2),setrlimit(2),sigaction(2),siglongjmp(3),sigsetjmp(3),signal(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/