sigaltstack系统调用及示例

sigaltstack 函数详解

  1. 函数介绍

sigaltstack 系统调用及示例,sigaltstack是Linux系统调用,用于设置和获取信号处理程序的备用栈(alternate signal stack)。当进程收到信号时,内核通常在当前栈上执行信号处理程序。使用 sigaltstack 可以为信号处理程序指定一个独立的栈空间,这对于处理栈溢出等异常情况特别有用。

  1. 函数原型
1
2
3
#include <signal.h>
int sigaltstack(const stack_t *ss, stack_t *oss);

  1. 功能

sigaltstack 允许进程为信号处理程序设置一个备用的栈空间。当信号被递送到使用备用栈的信号处理程序时,内核会切换到备用栈执行信号处理程序,执行完毕后再切换回原来的栈。

  1. 参数
  • *const stack_t ss: 指向新栈设置的指针(NULL表示不改变当前设置)

  • *stack_t oss: 指向存储旧栈设置的指针(NULL表示不获取旧设置)

  1. 返回值
  • 成功: 返回0

  • 失败: 返回-1,并设置errno

  1. 相似函数,或关联函数
  • signal/sigaction: 设置信号处理程序

  • sigprocmask: 设置信号屏蔽字

  • setjmp/longjmp: 非局部跳转

  • getcontext/setcontext: 上下文操作

  1. 示例代码

示例1:基础sigaltstack使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#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, &current_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, &current_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:栈溢出保护演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#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, &current_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&#91;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:多信号处理程序管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#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, &current_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, &current_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:线程安全的信号栈管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#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, &current_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&#91;num_threads];
thread_stack_manager_t managers&#91;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&#91;i], i + 1) != 0) {
printf("初始化线程 %d 失败\n", i + 1);
// 清理已分配的资源
for (int j = 0; j < i; j++) {
free(managers&#91;j].stack_buffer);
}
return -1;
}

if (pthread_create(&threads&#91;i], NULL, thread_worker, &managers&#91;i]) != 0) {
printf("创建线程 %d 失败\n", i + 1);
free(managers&#91;i].stack_buffer);
// 清理已分配的资源
for (int j = 0; j < i; j++) {
free(managers&#91;j].stack_buffer);
}
return -1;
}

managers&#91;i].thread_id = threads&#91;i];
printf("创建线程 %d: ID=%lu\n", i + 1, (unsigned long)threads&#91;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&#91;i], &result);
printf("线程 %d 已完成\n", i + 1);

// 清理资源
free(managers&#91;i].stack_buffer);
}

return 0;
}

int main() {
return demo_thread_safe_signal_stacks();
}

示例5:信号栈监控和调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#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&#91;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&#91;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内核

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

权限要求: 通常不需要特殊权限

架构支持: 支持所有主流架构

栈大小考虑:

最小大小: 至少MINSIGSTKSZ字节

推荐大小: 使用SIGSTKSZ或更大

动态分配: 建议在堆上分配栈空间

错误处理:

ENOMEM: 内存不足

EINVAL: 参数无效

EPERM: 权限不足

安全考虑:

栈溢出保护: 备用栈可以防止主栈溢出

信号安全: 确保信号处理程序的安全执行

资源管理: 及时释放分配的栈空间

最佳实践:

适当大小: 根据信号处理程序的需求分配栈大小

错误检查: 始终检查sigaltstack的返回值

资源清理: 程序结束时释放栈空间

线程安全: 多线程环境中每个线程需要独立的栈

监控调试: 监控栈使用情况以便调试

信号栈标志说明

SS_ONSTACK:

  • 含义: 当前正在使用备用栈执行信号处理程序

  • 用途: 检查信号处理程序是否在备用栈上执行

SS_DISABLE:

  • 含义: 备用栈被禁用

  • 用途: 禁用备用栈功能

SS_ENABLED:

  • 含义: 备用栈已启用但未使用

  • 用途: 正常状态,可以使用备用栈

相关常量

SIGSTKSZ:

  • 含义: 系统推荐的信号栈大小

  • 典型值: 8KB或更大

MINSIGSTKSZ:

  • 含义: 信号栈的最小大小

  • 典型值: 2KB

常见使用场景

1. 栈溢出保护:

1
2
3
4
5
6
7
// 为可能引起栈溢出的程序设置备用栈
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. 信号处理程序:

1
2
3
4
5
6
// 为信号处理程序设置独立的执行环境
struct sigaction sa;
sa.sa_handler = signal_handler;
sa.sa_flags = SA_ONSTACK;
sigaction(SIGSEGV, &sa, NULL);

3. 多线程应用:

1
2
3
4
5
6
7
8
9
10
// 每个线程设置独立的信号栈
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,可以构建更加健壮和安全的信号处理系统。在实际应用中,需要注意栈大小、错误处理和资源管理等关键问题。

data-ad-format="auto" data-full-width-responsive="true">