]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/stacktrace/example/terminate_handler.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / stacktrace / example / terminate_handler.cpp
CommitLineData
1e59de90 1// Copyright Antony Polukhin, 2016-2022.
b32b8144
FG
2//
3// Distributed under the Boost Software License, Version 1.0. (See
4// accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#include <boost/array.hpp>
8BOOST_NOINLINE void foo(int i);
9BOOST_NOINLINE void bar(int i);
10
11BOOST_NOINLINE void bar(int i) {
12 boost::array<int, 5> a = {{-1, -231, -123, -23, -32}};
13 if (i >= 0) {
14 foo(a[i]);
15 } else {
16 std::terminate();
17 }
18}
19
20BOOST_NOINLINE void foo(int i) {
21 bar(--i);
22}
23
24////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
25
1e59de90 26//[getting_started_signal_handlers
b32b8144
FG
27
28#include <signal.h> // ::signal, ::raise
29#include <boost/stacktrace.hpp>
30
31void my_signal_handler(int signum) {
32 ::signal(signum, SIG_DFL);
1e59de90
TL
33
34 // Outputs nothing or trash on majority of platforms
b32b8144 35 boost::stacktrace::safe_dump_to("./backtrace.dump");
1e59de90 36
b32b8144
FG
37 ::raise(SIGABRT);
38}
39//]
40
41void setup_handlers() {
1e59de90 42//[getting_started_setup_signel_handlers
b32b8144
FG
43 ::signal(SIGSEGV, &my_signal_handler);
44 ::signal(SIGABRT, &my_signal_handler);
45//]
46}
47
1e59de90
TL
48
49//[getting_started_terminate_handlers
50#include <cstdlib> // std::abort
51#include <exception> // std::set_terminate
52#include <iostream> // std::cerr
53
54#include <boost/stacktrace.hpp>
55
56void my_terminate_handler() {
57 try {
58 std::cerr << boost::stacktrace::stacktrace();
59 } catch (...) {}
60 std::abort();
61}
62//]
63
b32b8144
FG
64////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
65
66BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;
67
68//[getting_started_terminate_handlers_shmem
69#include <boost/stacktrace.hpp>
70#include <boost/interprocess/shared_memory_object.hpp>
71#include <boost/interprocess/mapped_region.hpp>
72
73boost::interprocess::shared_memory_object g_shm; // inited at program start
74boost::interprocess::mapped_region g_region; // inited at program start
75
76
77void my_signal_handler2(int signum) {
78 ::signal(signum, SIG_DFL);
79 void** f = static_cast<void**>(g_region.get_address());
80 *f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace.
81 boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));
82
83 ::raise(SIGABRT);
84}
85//]
86
87#include <iostream> // std::cerr
88#include <fstream> // std::ifstream
89#include <boost/filesystem/path.hpp>
90#include <boost/filesystem/operations.hpp>
91
92
93inline void copy_and_run(const char* exec_name, char param, bool not_null) {
94 std::cout << "Running with param " << param << std::endl;
95 boost::filesystem::path command = exec_name;
96 command = command.parent_path() / (command.stem().string() + param + command.extension().string());
97 boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists);
98
99 boost::filesystem::path command_args = command;
100 command_args += ' ';
101 command_args += param;
102 const int ret = std::system(command_args.string().c_str());
103
104 std::cout << "End Running with param " << param << "; ret code is " << ret << std::endl;
105 boost::system::error_code ignore;
106 boost::filesystem::remove(command, ignore);
107 if (not_null && !ret) {
108 std::exit(97);
109 } else if (!not_null && ret) {
110 std::exit(ret);
111 }
112}
113
1e59de90
TL
114int run_0(const char* /*argv*/[]) {
115//[getting_started_setup_terminate_handlers
116 std::set_terminate(&my_terminate_handler);
117//]
118 foo(5);
119 return 1;
120}
121
122
b32b8144
FG
123int run_1(const char* /*argv*/[]) {
124 setup_handlers();
125 foo(5);
126 return 11;
127}
128
129int run_2(const char* argv[]) {
130 if (!boost::filesystem::exists("./backtrace.dump")) {
131 if (std::string(argv[0]).find("noop") == std::string::npos) {
132 return 21;
133 }
134
135 boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(std::cin);
136 if (st) {
137 return 22;
138 }
139 return 0;
140 }
141
142//[getting_started_on_program_restart
143 if (boost::filesystem::exists("./backtrace.dump")) {
144 // there is a backtrace
145 std::ifstream ifs("./backtrace.dump");
146
147 boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
148 std::cout << "Previous run crashed:\n" << st << std::endl; /*<-*/
149
150 if (!st) {
151 return 23;
152 } /*->*/
153
154 // cleaning up
155 ifs.close();
156 boost::filesystem::remove("./backtrace.dump");
157 }
158//]
159
160 return 0;
161}
162
163
164int run_3(const char* /*argv*/[]) {
165 using namespace boost::interprocess;
166 {
167 shared_memory_object shm_obj(open_or_create, "shared_memory", read_write);
168 shm_obj.swap(g_shm);
169 }
170 g_shm.truncate(shared_memory_size);
171
172 {
173 mapped_region m(g_shm, read_write, 0, shared_memory_size);
174 m.swap(g_region);
175 }
176 void** f = static_cast<void**>(g_region.get_address());
177 *f = 0;
178
179 ::signal(SIGSEGV, &my_signal_handler2);
180 ::signal(SIGABRT, &my_signal_handler2);
181 foo(5);
182 return 31;
183}
184
185int run_4(const char* argv[]) {
186 using namespace boost::interprocess;
187 {
188 shared_memory_object shm_obj(open_only, "shared_memory", read_write);
189 shm_obj.swap(g_shm);
190 }
191
192 {
193 mapped_region m(g_shm, read_write, 0, shared_memory_size);
194 m.swap(g_region);
195 }
196
197//[getting_started_on_program_restart_shmem
198 void** f = static_cast<void**>(g_region.get_address());
199 if (*f) { // Checking if memory constains stacktrace.
200 boost::stacktrace::stacktrace st
201 = boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));
202
203 std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
204 *f = 0; /*<-*/
205 shared_memory_object::remove("shared_memory");
206 if (std::string(argv[0]).find("noop") == std::string::npos) {
207 if (!st) {
208 return 43;
209 }
210 } else {
211 if (st) {
212 return 44;
213 }
214 }
215 } else {
216 return 42; /*->*/
217 }
218//]
219
220
221 return 0;
222}
223
224#include <sstream>
225
226int test_inplace() {
227 const bool is_noop = !boost::stacktrace::stacktrace();
228
229 {
230 // This is very dependent on compiler and link flags. No sane way to make it work, because:
231 // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
232 // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
233 const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump");
234 boost::stacktrace::stacktrace ss2;
235 std::ifstream ifs("./backtrace2.dump");
236 boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
237 ifs.close();
238 boost::filesystem::remove("./backtrace2.dump");
239
240 if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) {
241 std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
242 } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
243 std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
244 }
245 }
246
247 {
248 // This is very dependent on compiler and link flags. No sane way to make it work, because:
249 // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
250 // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
251 void* data[1024];
252 const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data));
253 boost::stacktrace::stacktrace ss2;
254 boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data));
255
256 if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) {
257 std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
258 } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
259 std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
260 }
261 }
262
263 {
264 void* data[1024];
265 boost::stacktrace::safe_dump_to(1024, data, sizeof(data));
266 if (boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
267 std::cerr << "Stacktrace not empty!\n";
268 return 55;
269 }
270 }
271
272 {
273 void* data[1024];
274 boost::stacktrace::safe_dump_to(1, data, sizeof(data));
275 if (!is_noop && !boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
276 std::cerr << "Stacktrace empty!\n";
277 return 56;
278 }
279 const std::size_t size_1_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
280 boost::stacktrace::safe_dump_to(0, data, sizeof(data));
281 const std::size_t size_0_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
282
283 if (!is_noop && (size_1_skipped + 1 != size_0_skipped)) {
284 std::cerr << "failed to skip 1 frame!\n";
285 return 57;
286 }
287 }
288
289 {
290 boost::stacktrace::safe_dump_to(0, 1, "./backtrace3.dump");
291 std::ifstream ifs("./backtrace3.dump");
292 boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
293 ifs.close();
294
295 boost::stacktrace::safe_dump_to(1, 1, "./backtrace3.dump");
296 ifs.open("./backtrace3.dump");
297 boost::stacktrace::stacktrace ss2 = boost::stacktrace::stacktrace::from_dump(ifs);
298 ifs.close();
299
300 boost::filesystem::remove("./backtrace3.dump");
301
11fdf7f2
TL
302#ifdef BOOST_WINDOWS
303 // `ss2` could be empty on some combinations of Windows+MSVC.
304 if (!ss2) {
305 return 0;
306 }
307#endif
308
b32b8144
FG
309 if (ss1.size() != ss2.size()) {
310 std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
311 return 58;
312 }
313
314 if (!is_noop && ss1.size() != 1) {
315 std::cerr << "Stacktraces does not have size 1:\n" << ss1 << '\n';
316 return 59;
317 }
318
319 if (ss1 && ss1[0].address() == ss2[0].address()) {
320 std::cerr << "Stacktraces must differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
321 return 60;
322 }
323 }
324
325 return 0;
326}
327
328
329int main(int argc, const char* argv[]) {
330 if (argc < 2) {
1e59de90 331 // On Windows the debugger could be active. In that case tests hang and the CI run fails.
11fdf7f2 332#ifndef BOOST_WINDOWS
1e59de90
TL
333 copy_and_run(argv[0], '0', true);
334
b32b8144
FG
335 // We are copying files to make sure that stacktrace printing works independently from executable name
336 copy_and_run(argv[0], '1', true);
337 copy_and_run(argv[0], '2', false);
338
11fdf7f2 339 // There are some issues with async-safety of shared memory writes on Windows.
b32b8144
FG
340 copy_and_run(argv[0], '3', true);
341 copy_and_run(argv[0], '4', false);
342#endif
343
344 return test_inplace();
345 }
346
347 switch (argv[1][0]) {
1e59de90 348 case '0': return run_0(argv);
b32b8144
FG
349 case '1': return run_1(argv);
350 case '2': return run_2(argv);
351 case '3': return run_3(argv);
352 case '4': return run_4(argv);
353 }
354
355 return 404;
356}
357
358