1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Test that signal delivery is able to expand the stack segment without |
4 | * triggering a SEGV. |
5 | * |
6 | * Based on test code by Tom Lane. |
7 | */ |
8 | |
9 | #include <err.h> |
10 | #include <stdio.h> |
11 | #include <stdlib.h> |
12 | #include <signal.h> |
13 | #include <sys/types.h> |
14 | #include <unistd.h> |
15 | |
16 | #include "../pmu/lib.h" |
17 | #include "utils.h" |
18 | |
19 | #define _KB (1024) |
20 | #define _MB (1024 * 1024) |
21 | |
22 | static char *stack_base_ptr; |
23 | static char *stack_top_ptr; |
24 | |
25 | static volatile sig_atomic_t sig_occurred = 0; |
26 | |
27 | static void sigusr1_handler(int signal_arg) |
28 | { |
29 | sig_occurred = 1; |
30 | } |
31 | |
32 | static int consume_stack(unsigned int stack_size, union pipe write_pipe) |
33 | { |
34 | char stack_cur; |
35 | |
36 | if ((stack_base_ptr - &stack_cur) < stack_size) |
37 | return consume_stack(stack_size, write_pipe); |
38 | else { |
39 | stack_top_ptr = &stack_cur; |
40 | |
41 | FAIL_IF(notify_parent(write_pipe)); |
42 | |
43 | while (!sig_occurred) |
44 | barrier(); |
45 | } |
46 | |
47 | return 0; |
48 | } |
49 | |
50 | static int child(unsigned int stack_size, union pipe write_pipe) |
51 | { |
52 | struct sigaction act; |
53 | char stack_base; |
54 | |
55 | act.sa_handler = sigusr1_handler; |
56 | sigemptyset(&act.sa_mask); |
57 | act.sa_flags = 0; |
58 | if (sigaction(SIGUSR1, &act, NULL) < 0) |
59 | err(1, "sigaction" ); |
60 | |
61 | stack_base_ptr = (char *) (((size_t) &stack_base + 65535) & ~65535UL); |
62 | |
63 | FAIL_IF(consume_stack(stack_size, write_pipe)); |
64 | |
65 | printf("size 0x%06x: OK, stack base %p top %p (%zx used)\n" , |
66 | stack_size, stack_base_ptr, stack_top_ptr, |
67 | stack_base_ptr - stack_top_ptr); |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | static int test_one_size(unsigned int stack_size) |
73 | { |
74 | union pipe read_pipe, write_pipe; |
75 | pid_t pid; |
76 | |
77 | FAIL_IF(pipe(read_pipe.fds) == -1); |
78 | FAIL_IF(pipe(write_pipe.fds) == -1); |
79 | |
80 | pid = fork(); |
81 | if (pid == 0) { |
82 | close(read_pipe.read_fd); |
83 | close(write_pipe.write_fd); |
84 | exit(child(stack_size, write_pipe: read_pipe)); |
85 | } |
86 | |
87 | close(read_pipe.write_fd); |
88 | close(write_pipe.read_fd); |
89 | FAIL_IF(sync_with_child(read_pipe, write_pipe)); |
90 | |
91 | kill(pid, SIGUSR1); |
92 | |
93 | FAIL_IF(wait_for_child(pid)); |
94 | |
95 | close(read_pipe.read_fd); |
96 | close(write_pipe.write_fd); |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | int test(void) |
102 | { |
103 | unsigned int i, size; |
104 | |
105 | // Test with used stack from 1MB - 64K to 1MB + 64K |
106 | // Increment by 64 to get more coverage of odd sizes |
107 | for (i = 0; i < (128 * _KB); i += 64) { |
108 | size = i + (1 * _MB) - (64 * _KB); |
109 | FAIL_IF(test_one_size(stack_size: size)); |
110 | } |
111 | |
112 | return 0; |
113 | } |
114 | |
115 | int main(void) |
116 | { |
117 | return test_harness(test, "stack_expansion_signal" ); |
118 | } |
119 | |