Commit | Line | Data |
---|---|---|
d273fd4b MD |
1 | // SPDX-License-Identifier: MIT |
2 | // SPDX-FileCopyrightText: 2024 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
3 | /* | |
4 | * rseq memory pool test. | |
5 | */ | |
6 | ||
7 | #ifndef _GNU_SOURCE | |
8 | #define _GNU_SOURCE | |
9 | #endif | |
10 | #include <assert.h> | |
11 | #include <sched.h> | |
12 | #include <signal.h> | |
13 | #include <stdio.h> | |
14 | #include <string.h> | |
15 | #include <sys/time.h> | |
16 | #include <inttypes.h> | |
17 | #include <stdlib.h> | |
c15b99f6 OD |
18 | #include <sys/wait.h> |
19 | #include <unistd.h> | |
d273fd4b MD |
20 | |
21 | #include <rseq/mempool.h> | |
22 | ||
23 | #include "list.h" | |
24 | #include "tap.h" | |
25 | ||
26 | struct test_data { | |
27 | uintptr_t value; | |
28 | struct test_data __rseq_percpu *backref; | |
29 | struct list_head node; | |
30 | }; | |
31 | ||
f2981623 | 32 | static void test_mempool_fill(size_t stride) |
d273fd4b MD |
33 | { |
34 | struct test_data __rseq_percpu *ptr; | |
84a5a73a | 35 | struct test_data *iter, *tmp; |
0ba2a93e MD |
36 | struct rseq_mempool *mempool; |
37 | struct rseq_mempool_attr *attr; | |
d273fd4b MD |
38 | uint64_t count = 0; |
39 | LIST_HEAD(list); | |
40 | int ret, i; | |
41 | ||
0ba2a93e | 42 | attr = rseq_mempool_attr_create(); |
a8ad787a | 43 | ok(attr, "Create pool attribute"); |
0ba2a93e | 44 | ret = rseq_mempool_attr_set_robust(attr); |
d273fd4b MD |
45 | ok(ret == 0, "Setting mempool robust attribute"); |
46 | ||
0ba2a93e | 47 | mempool = rseq_mempool_create("test_data", |
d273fd4b | 48 | sizeof(struct test_data), |
f2981623 MD |
49 | stride, CPU_SETSIZE, attr); |
50 | ok(mempool, "Create mempool of size %zu", stride); | |
0ba2a93e | 51 | rseq_mempool_attr_destroy(attr); |
d273fd4b MD |
52 | |
53 | for (;;) { | |
54 | struct test_data *cpuptr; | |
55 | ||
15da5c27 | 56 | ptr = (struct test_data __rseq_percpu *) rseq_mempool_percpu_zmalloc(mempool); |
d273fd4b MD |
57 | if (!ptr) |
58 | break; | |
59 | /* Link items in cpu 0. */ | |
06e0b1c0 | 60 | cpuptr = rseq_percpu_ptr(ptr, 0, stride); |
d273fd4b MD |
61 | cpuptr->backref = ptr; |
62 | /* Randomize items in list. */ | |
63 | if (count & 1) | |
64 | list_add(&cpuptr->node, &list); | |
65 | else | |
66 | list_add_tail(&cpuptr->node, &list); | |
67 | count++; | |
68 | } | |
69 | ||
f2981623 | 70 | ok(count * sizeof(struct test_data) == stride, "Allocated %" PRIu64 " objects in pool", count); |
d273fd4b MD |
71 | |
72 | list_for_each_entry(iter, &list, node) { | |
73 | ptr = iter->backref; | |
74 | for (i = 0; i < CPU_SETSIZE; i++) { | |
06e0b1c0 | 75 | struct test_data *cpuptr = rseq_percpu_ptr(ptr, i, stride); |
d273fd4b MD |
76 | |
77 | if (cpuptr->value != 0) | |
78 | abort(); | |
79 | cpuptr->value++; | |
80 | } | |
81 | } | |
82 | ||
83 | ok(1, "Check for pool content corruption"); | |
84 | ||
84a5a73a | 85 | list_for_each_entry_safe(iter, tmp, &list, node) { |
d273fd4b | 86 | ptr = iter->backref; |
15da5c27 | 87 | rseq_mempool_percpu_free(ptr, stride); |
d273fd4b | 88 | } |
0ba2a93e | 89 | ret = rseq_mempool_destroy(mempool); |
d273fd4b MD |
90 | ok(ret == 0, "Destroy mempool"); |
91 | } | |
92 | ||
0ba2a93e | 93 | static void test_robust_double_free(struct rseq_mempool *pool) |
c15b99f6 OD |
94 | { |
95 | struct test_data __rseq_percpu *ptr; | |
96 | ||
15da5c27 | 97 | ptr = (struct test_data __rseq_percpu *) rseq_mempool_percpu_malloc(pool); |
c15b99f6 | 98 | |
15da5c27 MD |
99 | rseq_mempool_percpu_free(ptr); |
100 | rseq_mempool_percpu_free(ptr); | |
c15b99f6 OD |
101 | } |
102 | ||
0ba2a93e | 103 | static void test_robust_corrupt_after_free(struct rseq_mempool *pool) |
c15b99f6 OD |
104 | { |
105 | struct test_data __rseq_percpu *ptr; | |
106 | struct test_data *cpuptr; | |
107 | ||
15da5c27 | 108 | ptr = (struct test_data __rseq_percpu *) rseq_mempool_percpu_malloc(pool); |
c15b99f6 OD |
109 | cpuptr = (struct test_data *) rseq_percpu_ptr(ptr, 0); |
110 | ||
15da5c27 | 111 | rseq_mempool_percpu_free(ptr); |
c15b99f6 OD |
112 | cpuptr->value = (uintptr_t) test_robust_corrupt_after_free; |
113 | ||
0ba2a93e | 114 | rseq_mempool_destroy(pool); |
c15b99f6 OD |
115 | } |
116 | ||
0ba2a93e | 117 | static void test_robust_memory_leak(struct rseq_mempool *pool) |
c15b99f6 | 118 | { |
15da5c27 | 119 | (void) rseq_mempool_percpu_malloc(pool); |
c15b99f6 | 120 | |
0ba2a93e | 121 | rseq_mempool_destroy(pool); |
c15b99f6 OD |
122 | } |
123 | ||
0ba2a93e | 124 | static void test_robust_free_list_corruption(struct rseq_mempool *pool) |
c15b99f6 OD |
125 | { |
126 | struct test_data __rseq_percpu *ptr; | |
127 | struct test_data *cpuptr; | |
128 | ||
15da5c27 | 129 | ptr = (struct test_data __rseq_percpu *) rseq_mempool_percpu_malloc(pool); |
c15b99f6 OD |
130 | cpuptr = (struct test_data *) rseq_percpu_ptr(ptr, 0); |
131 | ||
15da5c27 | 132 | rseq_mempool_percpu_free(ptr); |
c15b99f6 OD |
133 | |
134 | cpuptr->value = (uintptr_t) cpuptr; | |
135 | ||
15da5c27 MD |
136 | (void) rseq_mempool_percpu_malloc(pool); |
137 | (void) rseq_mempool_percpu_malloc(pool); | |
c15b99f6 OD |
138 | } |
139 | ||
0ba2a93e MD |
140 | static int run_robust_test(void (*test)(struct rseq_mempool*), |
141 | struct rseq_mempool *pool) | |
c15b99f6 OD |
142 | { |
143 | pid_t cpid; | |
144 | int status; | |
145 | ||
146 | cpid = fork(); | |
147 | ||
148 | switch (cpid) { | |
149 | case -1: | |
150 | return 0; | |
151 | case 0: | |
152 | test(pool); | |
153 | _exit(EXIT_FAILURE); | |
154 | default: | |
155 | waitpid(cpid, &status, 0); | |
156 | } | |
157 | ||
158 | if (WIFSIGNALED(status) && | |
159 | (SIGABRT == WTERMSIG(status))) | |
160 | return 1; | |
161 | ||
162 | return 0; | |
163 | } | |
164 | ||
165 | static void run_robust_tests(void) | |
166 | { | |
0ba2a93e MD |
167 | struct rseq_mempool_attr *attr; |
168 | struct rseq_mempool *pool; | |
c15b99f6 | 169 | |
0ba2a93e | 170 | attr = rseq_mempool_attr_create(); |
c15b99f6 | 171 | |
0ba2a93e | 172 | rseq_mempool_attr_set_robust(attr); |
c15b99f6 | 173 | |
0ba2a93e | 174 | pool = rseq_mempool_create("mempool-robust", |
c15b99f6 OD |
175 | sizeof(void*), RSEQ_PERCPU_STRIDE, 1, |
176 | attr); | |
177 | ||
0ba2a93e | 178 | rseq_mempool_attr_destroy(attr); |
c15b99f6 OD |
179 | |
180 | ok(run_robust_test(test_robust_double_free, pool), | |
181 | "robust-double-free"); | |
182 | ||
183 | ok(run_robust_test(test_robust_corrupt_after_free, pool), | |
184 | "robust-corrupt-after-free"); | |
185 | ||
186 | ok(run_robust_test(test_robust_memory_leak, pool), | |
187 | "robust-memory-leak"); | |
188 | ||
189 | ok(run_robust_test(test_robust_free_list_corruption, pool), | |
190 | "robust-free-list-corruption"); | |
191 | ||
0ba2a93e | 192 | rseq_mempool_destroy(pool); |
c15b99f6 OD |
193 | } |
194 | ||
d273fd4b MD |
195 | int main(void) |
196 | { | |
197 | size_t len; | |
198 | ||
579badcb MD |
199 | plan_no_plan(); |
200 | ||
d273fd4b MD |
201 | /* From 4kB to 4MB */ |
202 | for (len = 4096; len < 4096 * 1024; len <<= 1) { | |
203 | test_mempool_fill(len); | |
204 | } | |
205 | ||
c15b99f6 OD |
206 | run_robust_tests(); |
207 | ||
d273fd4b MD |
208 | exit(exit_status()); |
209 | } |