sigaltstack 函数详解
1. 函数介绍
sigaltstack
是Linux系统调用,用于设置和获取信号处理程序的备用栈(alternate signal stack)。当进程收到信号时,内核通常在当前栈上执行信号处理程序。使用 sigaltstack
可以为信号处理程序指定一个独立的栈空间,这对于处理栈溢出等异常情况特别有用。
2. 函数原型
#include <signal.h>
int sigaltstack(const stack_t *ss, stack_t *oss);
3. 功能
sigaltstack
允许进程为信号处理程序设置一个备用的栈空间。当信号被递送到使用备用栈的信号处理程序时,内核会切换到备用栈执行信号处理程序,执行完毕后再切换回原来的栈。
4. 参数
- *const stack_t ss: 指向新栈设置的指针(NULL表示不改变当前设置)
- *stack_t oss: 指向存储旧栈设置的指针(NULL表示不获取旧设置)
5. 返回值
- 成功: 返回0
- 失败: 返回-1,并设置errno
6. 相似函数,或关联函数
- signal/sigaction: 设置信号处理程序
- sigprocmask: 设置信号屏蔽字
- setjmp/longjmp: 非局部跳转
- getcontext/setcontext: 上下文操作
7. 示例代码
示例1:基础sigaltstack使用
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/**
* 信号栈结构体
*/
typedef struct {
void *stack_ptr;
size_t stack_size;
int is_active;
} signal_stack_t;
/**
* 显示当前信号栈信息
*/
void show_signal_stack_info() {
stack_t current_stack;
if (sigaltstack(NULL, ¤t_stack) == 0) {
printf("=== 当前信号栈信息 ===\n");
printf("栈指针: %p\n", current_stack.ss_sp);
printf("栈大小: %zu 字节\n", current_stack.ss_size);
printf("栈标志: ");
if (current_stack.ss_flags & SS_ONSTACK) {
printf("SS_ONSTACK (正在使用中)\n");
} else if (current_stack.ss_flags & SS_DISABLE) {
printf("SS_DISABLE (已禁用)\n");
} else {
printf("SS_ENABLED (已启用)\n");
}
printf("\n");
} else {
printf("获取信号栈信息失败: %s\n", strerror(errno));
}
}
/**
* 信号处理程序
*/
void signal_handler(int sig) {
stack_t current_stack;
printf("信号处理程序执行中 (信号: %d)\n", sig);
// 检查当前是否在备用栈上
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_flags & SS_ONSTACK) {
printf(" ✓ 正在备用栈上执行\n");
} else {
printf(" ✗ 在主栈上执行\n");
}
}
printf(" 当前栈指针: %p\n", &sig);
printf(" 信号处理完成\n\n");
}
/**
* 演示基础sigaltstack使用方法
*/
int demo_sigaltstack_basic() {
stack_t new_stack, old_stack;
char *stack_buffer;
struct sigaction sa;
printf("=== 基础sigaltstack使用示例 ===\n");
// 显示原始信号栈信息
printf("1. 原始信号栈信息:\n");
show_signal_stack_info();
// 分配备用栈空间
size_t stack_size = SIGSTKSZ; // 系统推荐的栈大小
stack_buffer = malloc(stack_size);
if (!stack_buffer) {
perror("分配栈空间失败");
return -1;
}
printf("2. 分配备用栈空间:\n");
printf(" 栈大小: %zu 字节\n", stack_size);
printf(" 栈地址: %p\n", (void*)stack_buffer);
// 设置备用栈
new_stack.ss_sp = stack_buffer;
new_stack.ss_size = stack_size;
new_stack.ss_flags = 0; // 启用栈
printf("3. 设置备用信号栈:\n");
if (sigaltstack(&new_stack, &old_stack) == 0) {
printf(" ✓ 备用栈设置成功\n");
show_signal_stack_info();
} else {
printf(" ✗ 备用栈设置失败: %s\n", strerror(errno));
free(stack_buffer);
return -1;
}
// 设置使用备用栈的信号处理程序
printf("4. 设置信号处理程序:\n");
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK; // 使用备用栈
if (sigaction(SIGUSR1, &sa, NULL) == 0) {
printf(" ✓ 信号处理程序设置成功 (使用备用栈)\n");
} else {
printf(" ✗ 信号处理程序设置失败: %s\n", strerror(errno));
free(stack_buffer);
return -1;
}
// 发送信号测试
printf("5. 发送测试信号:\n");
if (kill(getpid(), SIGUSR1) == 0) {
printf(" ✓ 信号发送成功\n");
sleep(1); // 等待信号处理完成
} else {
printf(" ✗ 信号发送失败: %s\n", strerror(errno));
}
// 禁用备用栈
printf("6. 禁用备用栈:\n");
stack_t disable_stack;
disable_stack.ss_flags = SS_DISABLE;
if (sigaltstack(&disable_stack, NULL) == 0) {
printf(" ✓ 备用栈禁用成功\n");
show_signal_stack_info();
} else {
printf(" ✗ 备用栈禁用失败: %s\n", strerror(errno));
}
// 清理资源
free(stack_buffer);
return 0;
}
int main() {
return demo_sigaltstack_basic();
}
示例2:栈溢出保护演示
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <setjmp.h>
/**
* 栈溢出保护结构
*/
typedef struct {
stack_t alt_stack;
char *stack_buffer;
sigjmp_buf jump_buffer;
int overflow_detected;
} stack_protection_t;
/**
* 栈溢出信号处理程序
*/
void stack_overflow_handler(int sig) {
printf("⚠ 检测到栈溢出异常 (信号: %d)\n", sig);
// 检查是否在备用栈上
stack_t current_stack;
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_flags & SS_ONSTACK) {
printf(" ✓ 在备用栈上安全处理异常\n");
} else {
printf(" ✗ 不在备用栈上 (异常情况)\n");
}
}
// 恢复到安全状态
printf(" 跳转到安全恢复点...\n");
siglongjmp(((stack_protection_t*)NULL)->jump_buffer, 1);
}
/**
* 递归函数(可能导致栈溢出)
*/
void recursive_function(int depth) {
char buffer[1024]; // 消耗栈空间
// 填充缓冲区以确保栈使用
memset(buffer, depth & 0xFF, sizeof(buffer));
printf("递归深度: %d, 栈地址: %p\n", depth, (void*)&buffer);
// 深度递归可能导致栈溢出
if (depth < 1000) { // 限制递归深度
recursive_function(depth + 1);
}
}
/**
* 安全的递归执行
*/
int safe_recursive_execution(stack_protection_t *protection) {
struct sigaction sa;
int result;
printf("=== 栈溢出保护演示 ===\n");
// 设置信号处理程序
memset(&sa, 0, sizeof(sa));
sa.sa_handler = stack_overflow_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGSEGV, &sa, NULL) != 0) {
printf("设置SIGSEGV处理程序失败: %s\n", strerror(errno));
return -1;
}
if (sigaction(SIGBUS, &sa, NULL) != 0) {
printf("设置SIGBUS处理程序失败: %s\n", strerror(errno));
return -1;
}
// 设置跳转点
result = sigsetjmp(protection->jump_buffer, 1);
if (result == 0) {
printf("开始安全递归执行...\n");
// 执行可能引起栈溢出的操作
recursive_function(0);
printf("递归执行正常完成\n");
return 0;
} else {
printf("✓ 从栈溢出异常中成功恢复\n");
return 1;
}
}
/**
* 演示栈溢出保护
*/
int demo_stack_overflow_protection() {
stack_protection_t protection = {0};
size_t stack_size = SIGSTKSZ * 2; // 更大的备用栈
printf("=== 栈溢出保护演示 ===\n");
// 分配备用栈
protection.stack_buffer = malloc(stack_size);
if (!protection.stack_buffer) {
perror("分配备用栈失败");
return -1;
}
printf("分配备用栈: %zu 字节\n", stack_size);
// 设置备用栈
protection.alt_stack.ss_sp = protection.stack_buffer;
protection.alt_stack.ss_size = stack_size;
protection.alt_stack.ss_flags = 0;
if (sigaltstack(&protection.alt_stack, NULL) != 0) {
printf("设置备用栈失败: %s\n", strerror(errno));
free(protection.stack_buffer);
return -1;
}
printf("备用栈设置成功\n");
show_signal_stack_info();
// 执行安全递归
int result = safe_recursive_execution(&protection);
// 清理资源
free(protection.stack_buffer);
return result;
}
// 辅助函数声明
void show_signal_stack_info();
int main() {
return demo_stack_overflow_protection();
}
示例3:多信号处理程序管理
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
/**
* 多栈管理器
*/
typedef struct {
stack_t stack1;
stack_t stack2;
char *buffer1;
char *buffer2;
int current_stack;
} multi_stack_manager_t;
/**
* 信号处理程序1(使用栈1)
*/
void signal_handler_1(int sig) {
printf("信号处理程序1执行 (信号: %d)\n", sig);
stack_t current_stack;
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_flags & SS_ONSTACK) {
printf(" 使用备用栈1执行\n");
}
}
printf(" 处理程序1完成\n");
}
/**
* 信号处理程序2(使用栈2)
*/
void signal_handler_2(int sig) {
printf("信号处理程序2执行 (信号: %d)\n", sig);
stack_t current_stack;
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_flags & SS_ONSTACK) {
printf(" 使用备用栈2执行\n");
}
}
printf(" 处理程序2完成\n");
}
/**
* 初始化多栈管理器
*/
int init_multi_stack_manager(multi_stack_manager_t *manager) {
size_t stack_size = SIGSTKSZ;
printf("=== 多栈管理器初始化 ===\n");
// 分配两个栈空间
manager->buffer1 = malloc(stack_size);
manager->buffer2 = malloc(stack_size);
if (!manager->buffer1 || !manager->buffer2) {
printf("分配栈空间失败\n");
if (manager->buffer1) free(manager->buffer1);
if (manager->buffer2) free(manager->buffer2);
return -1;
}
printf("栈1地址: %p, 大小: %zu\n", (void*)manager->buffer1, stack_size);
printf("栈2地址: %p, 大小: %zu\n", (void*)manager->buffer2, stack_size);
// 初始化栈结构
manager->stack1.ss_sp = manager->buffer1;
manager->stack1.ss_size = stack_size;
manager->stack1.ss_flags = 0;
manager->stack2.ss_sp = manager->buffer2;
manager->stack2.ss_size = stack_size;
manager->stack2.ss_flags = 0;
manager->current_stack = 0;
return 0;
}
/**
* 切换备用栈
*/
int switch_alternate_stack(multi_stack_manager_t *manager, int stack_id) {
stack_t *target_stack = (stack_id == 1) ? &manager->stack1 : &manager->stack2;
printf("切换到备用栈 %d\n", stack_id);
if (sigaltstack(target_stack, NULL) == 0) {
printf("✓ 成功切换到备用栈 %d\n", stack_id);
manager->current_stack = stack_id;
return 0;
} else {
printf("✗ 切换备用栈 %d 失败: %s\n", stack_id, strerror(errno));
return -1;
}
}
/**
* 演示多信号处理程序
*/
int demo_multi_signal_handlers() {
multi_stack_manager_t manager = {0};
struct sigaction sa1, sa2;
printf("=== 多信号处理程序演示 ===\n");
// 初始化多栈管理器
if (init_multi_stack_manager(&manager) != 0) {
printf("初始化多栈管理器失败\n");
return -1;
}
// 设置信号处理程序1(使用栈1)
printf("\n设置信号处理程序1:\n");
switch_alternate_stack(&manager, 1);
memset(&sa1, 0, sizeof(sa1));
sa1.sa_handler = signal_handler_1;
sigemptyset(&sa1.sa_mask);
sa1.sa_flags = SA_ONSTACK;
if (sigaction(SIGUSR1, &sa1, NULL) == 0) {
printf("✓ 信号处理程序1设置成功\n");
} else {
printf("✗ 信号处理程序1设置失败: %s\n", strerror(errno));
}
// 设置信号处理程序2(使用栈2)
printf("\n设置信号处理程序2:\n");
switch_alternate_stack(&manager, 2);
memset(&sa2, 0, sizeof(sa2));
sa2.sa_handler = signal_handler_2;
sigemptyset(&sa2.sa_mask);
sa2.sa_flags = SA_ONSTACK;
if (sigaction(SIGUSR2, &sa2, NULL) == 0) {
printf("✓ 信号处理程序2设置成功\n");
} else {
printf("✗ 信号处理程序2设置失败: %s\n", strerror(errno));
}
// 测试信号处理
printf("\n测试信号处理:\n");
// 发送SIGUSR1
printf("发送SIGUSR1信号:\n");
switch_alternate_stack(&manager, 1);
if (kill(getpid(), SIGUSR1) == 0) {
printf("✓ SIGUSR1发送成功\n");
sleep(1);
}
// 发送SIGUSR2
printf("发送SIGUSR2信号:\n");
switch_alternate_stack(&manager, 2);
if (kill(getpid(), SIGUSR2) == 0) {
printf("✓ SIGUSR2发送成功\n");
sleep(1);
}
// 清理资源
free(manager.buffer1);
free(manager.buffer2);
return 0;
}
int main() {
return demo_multi_signal_handlers();
}
示例4:线程安全的信号栈管理
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
/**
* 线程信号栈管理器
*/
typedef struct {
stack_t signal_stack;
char *stack_buffer;
pthread_t thread_id;
int thread_num;
} thread_stack_manager_t;
/**
* 线程信号处理程序
*/
void thread_signal_handler(int sig) {
pthread_t current_thread = pthread_self();
printf("线程 %lu 收到信号 %d\n", (unsigned long)current_thread, sig);
stack_t current_stack;
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_flags & SS_ONSTACK) {
printf(" 线程 %lu 在备用栈上处理信号\n", (unsigned long)current_thread);
} else {
printf(" 线程 %lu 在主栈上处理信号\n", (unsigned long)current_thread);
}
}
printf(" 线程 %lu 信号处理完成\n", (unsigned long)current_thread);
}
/**
* 初始化线程栈管理器
*/
int init_thread_stack_manager(thread_stack_manager_t *manager, int thread_num) {
size_t stack_size = SIGSTKSZ;
manager->thread_num = thread_num;
manager->thread_id = pthread_self();
// 分配栈空间
manager->stack_buffer = malloc(stack_size);
if (!manager->stack_buffer) {
printf("线程 %d: 分配栈空间失败\n", thread_num);
return -1;
}
// 初始化栈结构
manager->signal_stack.ss_sp = manager->stack_buffer;
manager->signal_stack.ss_size = stack_size;
manager->signal_stack.ss_flags = 0;
printf("线程 %d: 分配备用栈 %p, 大小 %zu\n",
thread_num, (void*)manager->stack_buffer, stack_size);
return 0;
}
/**
* 线程工作函数
*/
void* thread_worker(void *arg) {
thread_stack_manager_t *manager = (thread_stack_manager_t*)arg;
struct sigaction sa;
sigset_t set;
printf("工作线程 %d 启动 (ID: %lu)\n",
manager->thread_num, (unsigned long)manager->thread_id);
// 设置备用栈
if (sigaltstack(&manager->signal_stack, NULL) != 0) {
printf("线程 %d: 设置备用栈失败: %s\n",
manager->thread_num, strerror(errno));
return NULL;
}
printf("线程 %d: 备用栈设置成功\n", manager->thread_num);
// 设置信号处理程序
memset(&sa, 0, sizeof(sa));
sa.sa_handler = thread_signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGUSR1, &sa, NULL) != 0) {
printf("线程 %d: 设置信号处理程序失败: %s\n",
manager->thread_num, strerror(errno));
return NULL;
}
printf("线程 %d: 信号处理程序设置成功\n", manager->thread_num);
// 阻塞SIGUSR1以便测试
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &set, NULL);
// 执行工作
for (int i = 0; i < 5; i++) {
printf("线程 %d: 工作中... (%d/5)\n", manager->thread_num, i + 1);
sleep(2);
}
// 解除阻塞并等待信号
printf("线程 %d: 等待信号...\n", manager->thread_num);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
// 等待一段时间让信号处理完成
sleep(2);
printf("线程 %d: 工作完成\n", manager->thread_num);
return NULL;
}
/**
* 演示线程安全的信号栈管理
*/
int demo_thread_safe_signal_stacks() {
const int num_threads = 3;
pthread_t threads[num_threads];
thread_stack_manager_t managers[num_threads];
sigset_t set;
printf("=== 线程安全的信号栈管理演示 ===\n");
// 阻塞SIGUSR1信号
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &set, NULL);
// 创建工作线程
printf("创建 %d 个工作线程:\n", num_threads);
for (int i = 0; i < num_threads; i++) {
if (init_thread_stack_manager(&managers[i], i + 1) != 0) {
printf("初始化线程 %d 失败\n", i + 1);
// 清理已分配的资源
for (int j = 0; j < i; j++) {
free(managers[j].stack_buffer);
}
return -1;
}
if (pthread_create(&threads[i], NULL, thread_worker, &managers[i]) != 0) {
printf("创建线程 %d 失败\n", i + 1);
free(managers[i].stack_buffer);
// 清理已分配的资源
for (int j = 0; j < i; j++) {
free(managers[j].stack_buffer);
}
return -1;
}
managers[i].thread_id = threads[i];
printf("创建线程 %d: ID=%lu\n", i + 1, (unsigned long)threads[i]);
}
// 等待线程启动
sleep(1);
// 向所有线程发送信号
printf("\n向所有线程发送SIGUSR1信号:\n");
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
for (int i = 0; i < num_threads; i++) {
// 注意:实际应用中需要更精确的线程信号发送方法
if (kill(getpid(), SIGUSR1) == 0) {
printf("向线程 %d 发送信号成功\n", i + 1);
} else {
printf("向线程 %d 发送信号失败: %s\n", i + 1, strerror(errno));
}
sleep(1); // 间隔发送
}
// 等待所有线程完成
printf("\n等待所有线程完成:\n");
for (int i = 0; i < num_threads; i++) {
void *result;
pthread_join(threads[i], &result);
printf("线程 %d 已完成\n", i + 1);
// 清理资源
free(managers[i].stack_buffer);
}
return 0;
}
int main() {
return demo_thread_safe_signal_stacks();
}
示例5:信号栈监控和调试
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/resource.h>
/**
* 信号栈监控器
*/
typedef struct {
stack_t original_stack;
stack_t current_stack;
int stack_switch_count;
size_t total_stack_size;
time_t last_switch_time;
} stack_monitor_t;
/**
* 详细的栈信息显示
*/
void show_detailed_stack_info(const char *context) {
stack_t stack_info;
printf("=== %s ===\n", context);
if (sigaltstack(NULL, &stack_info) == 0) {
printf("栈指针: %p\n", stack_info.ss_sp);
printf("栈大小: %zu 字节\n", stack_info.ss_size);
printf("栈标志: 0x%x\n", stack_info.ss_flags);
if (stack_info.ss_flags & SS_ONSTACK) {
printf("状态: 正在使用备用栈\n");
} else if (stack_info.ss_flags & SS_DISABLE) {
printf("状态: 备用栈已禁用\n");
} else {
printf("状态: 备用栈已启用但未使用\n");
}
// 计算栈使用情况(简化版)
void *current_sp;
asm volatile("mov %%rsp, %0" : "=r"(current_sp));
printf("当前栈指针: %p\n", current_sp);
if (stack_info.ss_sp) {
ptrdiff_t distance = (char*)current_sp - (char*)stack_info.ss_sp;
printf("距离栈底: %td 字节\n", distance);
if (distance > 0 && (size_t)distance < stack_info.ss_size) {
double usage = (double)distance / stack_info.ss_size * 100;
printf("栈使用率: %.1f%%\n", usage);
}
}
} else {
printf("获取栈信息失败: %s\n", strerror(errno));
}
printf("\n");
}
/**
* 信号处理程序(带监控)
*/
void monitored_signal_handler(int sig) {
static int call_count = 0;
call_count++;
printf("监控信号处理程序执行 (第 %d 次, 信号: %d)\n", call_count, sig);
show_detailed_stack_info("信号处理程序中的栈状态");
// 模拟一些栈使用
char local_buffer[512];
memset(local_buffer, call_count & 0xFF, sizeof(local_buffer));
printf(" 处理程序使用了 %zu 字节本地缓冲区\n", sizeof(local_buffer));
printf(" 处理程序执行完成\n\n");
}
/**
* 栈使用压力测试
*/
void stack_pressure_test(int depth) {
char buffer[1024]; // 每层消耗1KB栈空间
// 填充缓冲区
memset(buffer, depth & 0xFF, sizeof(buffer));
if (depth < 50) { // 限制递归深度
printf("递归深度: %d, 使用栈空间: %d KB\n", depth, depth);
stack_pressure_test(depth + 1);
} else {
printf("达到最大递归深度: %d\n", depth);
}
}
/**
* 演示信号栈监控和调试
*/
int demo_stack_monitoring() {
stack_t alt_stack, old_stack;
char *stack_buffer;
struct sigaction sa;
struct rlimit rl;
printf("=== 信号栈监控和调试演示 ===\n");
// 显示系统栈限制
printf("1. 系统栈限制信息:\n");
if (getrlimit(RLIMIT_STACK, &rl) == 0) {
printf(" 主栈大小限制: %ld 字节", rl.rlim_cur);
if (rl.rlim_cur == RLIM_INFINITY) {
printf(" (无限制)");
}
printf("\n");
printf(" 最大栈大小: %ld 字节", rl.rlim_max);
if (rl.rlim_max == RLIM_INFINITY) {
printf(" (无限制)");
}
printf("\n");
}
// 显示初始栈状态
show_detailed_stack_info("初始栈状态");
// 分配备用栈
size_t stack_size = SIGSTKSZ * 4; // 4倍标准大小
stack_buffer = malloc(stack_size);
if (!stack_buffer) {
perror("分配备用栈失败");
return -1;
}
printf("2. 分配备用栈:\n");
printf(" 请求大小: %zu 字节 (%.1f KB)\n", stack_size, stack_size / 1024.0);
printf(" 分配地址: %p\n", (void*)stack_buffer);
// 设置备用栈
alt_stack.ss_sp = stack_buffer;
alt_stack.ss_size = stack_size;
alt_stack.ss_flags = 0;
printf("3. 设置备用栈:\n");
if (sigaltstack(&alt_stack, &old_stack) == 0) {
printf(" ✓ 备用栈设置成功\n");
show_detailed_stack_info("设置备用栈后");
} else {
printf(" ✗ 备用栈设置失败: %s\n", strerror(errno));
free(stack_buffer);
return -1;
}
// 设置监控信号处理程序
printf("4. 设置监控信号处理程序:\n");
memset(&sa, 0, sizeof(sa));
sa.sa_handler = monitored_signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGUSR1, &sa, NULL) == 0) {
printf(" ✓ 监控信号处理程序设置成功\n");
} else {
printf(" ✗ 监控信号处理程序设置失败: %s\n", strerror(errno));
free(stack_buffer);
return -1;
}
// 发送多个信号进行测试
printf("5. 发送测试信号:\n");
for (int i = 1; i <= 3; i++) {
printf(" 发送第 %d 个信号:\n", i);
if (kill(getpid(), SIGUSR1) == 0) {
printf(" ✓ 信号发送成功\n");
sleep(1); // 等待处理完成
} else {
printf(" ✗ 信号发送失败: %s\n", strerror(errno));
}
}
// 栈压力测试
printf("6. 栈压力测试:\n");
printf(" 开始递归栈使用测试...\n");
stack_pressure_test(0);
printf(" 栈压力测试完成\n");
show_detailed_stack_info("压力测试后栈状态");
// 禁用备用栈
printf("7. 禁用备用栈:\n");
stack_t disable_stack;
disable_stack.ss_flags = SS_DISABLE;
if (sigaltstack(&disable_stack, NULL) == 0) {
printf(" ✓ 备用栈禁用成功\n");
show_detailed_stack_info("禁用备用栈后");
} else {
printf(" ✗ 备用栈禁用失败: %s\n", strerror(errno));
}
// 清理资源
free(stack_buffer);
printf("=== 监控演示完成 ===\n");
return 0;
}
int main() {
return demo_stack_monitoring();
}
sigaltstack 使用注意事项
系统要求:
- 内核版本: 支持信号备用栈的Linux内核
- 权限要求: 通常不需要特殊权限
- 架构支持: 支持所有主流架构
栈大小考虑:
- 最小大小: 至少MINSIGSTKSZ字节
- 推荐大小: 使用SIGSTKSZ或更大
- 动态分配: 建议在堆上分配栈空间
错误处理:
- ENOMEM: 内存不足
- EINVAL: 参数无效
- EPERM: 权限不足
安全考虑:
- 栈溢出保护: 备用栈可以防止主栈溢出
- 信号安全: 确保信号处理程序的安全执行
- 资源管理: 及时释放分配的栈空间
最佳实践:
- 适当大小: 根据信号处理程序的需求分配栈大小
- 错误检查: 始终检查sigaltstack的返回值
- 资源清理: 程序结束时释放栈空间
- 线程安全: 多线程环境中每个线程需要独立的栈
- 监控调试: 监控栈使用情况以便调试
信号栈标志说明
SS_ONSTACK:
- 含义: 当前正在使用备用栈执行信号处理程序
- 用途: 检查信号处理程序是否在备用栈上执行
SS_DISABLE:
- 含义: 备用栈被禁用
- 用途: 禁用备用栈功能
SS_ENABLED:
- 含义: 备用栈已启用但未使用
- 用途: 正常状态,可以使用备用栈
相关常量
SIGSTKSZ:
- 含义: 系统推荐的信号栈大小
- 典型值: 8KB或更大
MINSIGSTKSZ:
- 含义: 信号栈的最小大小
- 典型值: 2KB
常见使用场景
1. 栈溢出保护:
// 为可能引起栈溢出的程序设置备用栈
stack_t alt_stack;
alt_stack.ss_sp = malloc(SIGSTKSZ);
alt_stack.ss_size = SIGSTKSZ;
alt_stack.ss_flags = 0;
sigaltstack(&alt_stack, NULL);
2. 信号处理程序:
// 为信号处理程序设置独立的执行环境
struct sigaction sa;
sa.sa_handler = signal_handler;
sa.sa_flags = SA_ONSTACK;
sigaction(SIGSEGV, &sa, NULL);
3. 多线程应用:
// 每个线程设置独立的信号栈
void* thread_function(void *arg) {
stack_t thread_stack;
thread_stack.ss_sp = malloc(SIGSTKSZ);
thread_stack.ss_size = SIGSTKSZ;
thread_stack.ss_flags = 0;
sigaltstack(&thread_stack, NULL);
// 线程工作...
}
总结
sigaltstack
是Linux系统中重要的信号处理机制,提供了:
- 栈隔离: 为信号处理程序提供独立的执行环境
- 异常处理: 防止栈溢出等异常情况
- 安全执行: 确保信号处理程序的安全执行
- 灵活配置: 支持动态栈管理和配置
通过合理使用 sigaltstack
,可以构建更加健壮和安全的信号处理系统。在实际应用中,需要注意栈大小、错误处理和资源管理等关键问题。