Skip to content

Commit d26dc67

Browse files
committed
Implemented safe dumping and loading
1 parent d535c5a commit d26dc67

11 files changed

Lines changed: 253 additions & 162 deletions

File tree

example/terminate_handler.cpp

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ BOOST_NOINLINE void foo(int i) {
3434

3535
void my_signal_handler(int signum) {
3636
::signal(signum, SIG_DFL);
37-
boost::stacktrace::this_thread_frames::dump("./backtrace.dump");
37+
boost::stacktrace::safe_dump_to("./backtrace.dump");
3838
std::_Exit(-1);
3939
}
4040
//]
@@ -48,7 +48,9 @@ void setup_handlers() {
4848

4949

5050
#include <iostream> // std::cerr
51-
#include <boost/filesystem.hpp>
51+
#include <fstream> // std::ifstream
52+
#include <boost/filesystem/path.hpp>
53+
#include <boost/filesystem/operations.hpp>
5254

5355
int main(int argc, const char* argv[]) {
5456
if (argc < 2) {
@@ -59,7 +61,7 @@ int main(int argc, const char* argv[]) {
5961
boost::filesystem::copy_file(argv[0], command_1, boost::filesystem::copy_option::overwrite_if_exists);
6062
command_1 += " 1";
6163
if (std::system(command_1.string().c_str())) {
62-
std::exit(-1);
64+
std::exit(1);
6365
}
6466
}
6567

@@ -69,24 +71,48 @@ int main(int argc, const char* argv[]) {
6971
boost::filesystem::copy_file(argv[0], command_2, boost::filesystem::copy_option::overwrite_if_exists);
7072
command_2 += " 2";
7173
if (std::system(command_2.string().c_str())) {
72-
std::exit(-2);
74+
std::exit(2);
7375
}
7476
}
7577

7678
return 0;
7779
}
7880

79-
switch(argv[1][0]) {
80-
case '1':
81+
if (argv[1][0] == '1') {
8182
setup_handlers();
8283
foo(5);
83-
return -11;
84-
case '2':
85-
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump("./backtrace.dump");
86-
std::cout << st << std::endl;
84+
return 3;
85+
}
86+
87+
if (argv[1][0] != '2') {
88+
return 4;
89+
}
90+
91+
if (!boost::filesystem::exists("./backtrace.dump")) {
92+
if (std::string(argv[0]).find("noop") == std::string::npos) {
93+
return 5;
94+
}
95+
8796
return 0;
8897
}
89-
return 3;
98+
99+
if (boost::filesystem::exists("./backtrace.dump")) {
100+
// there is a backtrace
101+
std::ifstream ifs("./backtrace.dump");
102+
103+
boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
104+
std::cout << "Previous run crashed: " << st << std::endl; /*<-*/
105+
106+
if (!st) {
107+
return 6;
108+
} /*->*/
109+
// cleaning up
110+
boost::filesystem::remove("./backtrace.dump");
111+
}
112+
113+
114+
return 0;
115+
90116
}
91117

92118

include/boost/stacktrace/detail/frame_msvc.ipp

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,35 @@ std::string to_string(const frame* frames, std::size_t size) {
236236
return res;
237237
}
238238

239+
240+
std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
241+
return ::CaptureStackBackTrace(
242+
0,
243+
static_cast<boost::detail::winapi::ULONG_>(size),
244+
memory,
245+
0
246+
);
247+
}
248+
249+
std::size_t dump(void* fd, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
250+
if (!::WriteFile(fd, memory, sizeof(void*) * mem_size, 0, 0)) {
251+
return 0;
252+
}
253+
254+
return mem_size;
255+
}
256+
257+
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
258+
void* const fd = ::CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
259+
if (fd == INVALID_HANDLE_VALUE) {
260+
return 0;
261+
}
262+
263+
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
264+
::CloseHandle(fd);
265+
return size;
266+
}
267+
239268
} // namespace detail
240269

241270
std::string frame::name() const {
@@ -291,38 +320,6 @@ std::string to_string(const frame& f) {
291320
return res;
292321
}
293322

294-
295-
std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
296-
return ::CaptureStackBackTrace(
297-
0,
298-
static_cast<boost::detail::winapi::ULONG_>(size),
299-
memory,
300-
0
301-
);
302-
}
303-
304-
std::size_t this_thread_frames::dump(void* fd) BOOST_NOEXCEPT {
305-
BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = boost::stacktrace::detail::max_frames_dump;
306-
BOOST_CONSTEXPR_OR_CONST std::size_t frames_to_skip = 1;
307-
void* buf[buf_size];
308-
const std::size_t size = boost::stacktrace::this_thread_frames::collect(buf, buf_size);
309-
if (!::WriteFile(fd, buf + frames_to_skip, sizeof(void*) * (size - frames_to_skip), 0, 0)) {
310-
return 0;
311-
}
312-
313-
return size;
314-
}
315-
316-
std::size_t this_thread_frames::dump(const char* file) BOOST_NOEXCEPT {
317-
void* const fd = ::CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
318-
if (fd == INVALID_HANDLE_VALUE) {
319-
return 0;
320-
}
321-
const std::size_t size = boost::stacktrace::this_thread_frames::dump(fd);
322-
::CloseHandle(fd);
323-
return size;
324-
}
325-
326323
}} // namespace boost::stacktrace
327324

328325
#endif // BOOST_STACKTRACE_DETAIL_FRAME_MSVC_IPP

include/boost/stacktrace/detail/frame_noop.ipp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@ std::size_t from_dump(const char* /*filename*/, void** /*frames*/) {
2424
return 0;
2525
}
2626

27+
std::size_t this_thread_frames::collect(void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
28+
return 0;
29+
}
30+
31+
#if defined(BOOST_WINDOWS)
32+
std::size_t dump(void* /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
33+
return 0;
34+
}
35+
#else
36+
std::size_t dump(int /*fd*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
37+
return 0;
38+
}
39+
#endif
40+
41+
42+
std::size_t dump(const char* /*file*/, void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
43+
return 0;
44+
}
45+
2746
} // namespace detail
2847

2948
std::string frame::name() const {
@@ -42,25 +61,6 @@ std::string to_string(const frame& /*f*/) {
4261
return std::string();
4362
}
4463

45-
std::size_t this_thread_frames::collect(void** /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT {
46-
return 0;
47-
}
48-
49-
#if defined(BOOST_WINDOWS)
50-
std::size_t this_thread_frames::dump(void* /*fd*/) BOOST_NOEXCEPT {
51-
return 0;
52-
}
53-
#else
54-
std::size_t this_thread_frames::dump(int /*fd*/) BOOST_NOEXCEPT {
55-
return 0;
56-
}
57-
#endif
58-
59-
60-
61-
std::size_t this_thread_frames::dump(const char* /*file*/) BOOST_NOEXCEPT {
62-
return 0;
63-
}
6464

6565
}} // namespace boost::stacktrace
6666

include/boost/stacktrace/detail/frame_unwind.ipp

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -100,25 +100,6 @@ std::string to_string(const frame* frames, std::size_t size) {
100100
return res;
101101
}
102102

103-
} // namespace detail
104-
105-
106-
std::string frame::name() const {
107-
::Dl_info dli;
108-
const bool dl_ok = !!::dladdr(addr_, &dli);
109-
if (dl_ok && dli.dli_sname) {
110-
return boost::stacktrace::detail::try_demangle(dli.dli_sname);
111-
}
112-
113-
return boost::stacktrace::detail::name_impl(addr_);
114-
}
115-
116-
std::string to_string(const frame& f) {
117-
boost::stacktrace::detail::to_string_impl impl;
118-
return impl(f.address());
119-
}
120-
121-
122103
std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_NOEXCEPT {
123104
std::size_t frames_count = 0;
124105
if (!size) {
@@ -137,34 +118,48 @@ std::size_t this_thread_frames::collect(void** memory, std::size_t size) BOOST_N
137118
}
138119

139120

140-
std::size_t this_thread_frames::dump(int fd) BOOST_NOEXCEPT {
141-
BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = boost::stacktrace::detail::max_frames_dump;
142-
BOOST_CONSTEXPR_OR_CONST std::size_t frames_to_skip = 1;
143-
void* buf[buf_size];
144-
const std::size_t size = boost::stacktrace::this_thread_frames::collect(buf, buf_size);
145-
146-
// We do not retry, becase this function must be typically called from signal handler so it's:
121+
std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT {
122+
// We do not retry, because this function must be typically called from signal handler so it's:
147123
// * to scary to continue in case of EINTR
148124
// * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
149125
// so it seems that user does not want to block
150-
if (::write(fd, buf + frames_to_skip, sizeof(void*) * (size - frames_to_skip)) == -1) {
126+
if (::write(fd, memory, sizeof(void*) * size) == -1) {
151127
return 0;
152128
}
153129

154130
return size;
155131
}
156132

157-
std::size_t this_thread_frames::dump(const char* file) BOOST_NOEXCEPT {
133+
std::size_t dump(const char* file, void** memory, std::size_t mem_size) BOOST_NOEXCEPT {
158134
const int fd = ::open(file, O_CREAT | O_WRONLY | O_TRUNC, S_IFREG | S_IWUSR | S_IRUSR);
159135
if (fd == -1) {
160136
return 0;
161137
}
162138

163-
const std::size_t size = boost::stacktrace::this_thread_frames::dump(fd);
139+
const std::size_t size = boost::stacktrace::detail::dump(fd, memory, mem_size);
164140
::close(fd);
165141
return size;
166142
}
167143

144+
} // namespace detail
145+
146+
147+
std::string frame::name() const {
148+
::Dl_info dli;
149+
const bool dl_ok = !!::dladdr(addr_, &dli);
150+
if (dl_ok && dli.dli_sname) {
151+
return boost::stacktrace::detail::try_demangle(dli.dli_sname);
152+
}
153+
154+
return boost::stacktrace::detail::name_impl(addr_);
155+
}
156+
157+
std::string to_string(const frame& f) {
158+
boost::stacktrace::detail::to_string_impl impl;
159+
return impl(f.address());
160+
}
161+
162+
168163
}} // namespace boost::stacktrace
169164

170165
#endif // BOOST_STACKTRACE_DETAIL_FRAME_UNWIND_IPP

include/boost/stacktrace/detail/from_dump.ipp

Lines changed: 0 additions & 35 deletions
This file was deleted.

include/boost/stacktrace/frame.hpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ namespace detail {
5050

5151
enum helper{ max_frames_dump = 128 };
5252
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, void** frames);
53+
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, void** memory, std::size_t size) BOOST_NOEXCEPT;
54+
#if defined(BOOST_WINDOWS)
55+
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
56+
#else
57+
// POSIX
58+
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, void** memory, std::size_t size) BOOST_NOEXCEPT;
59+
#endif
60+
61+
62+
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
63+
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT;
64+
};
65+
5366
} // namespace detail
5467

5568
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
@@ -169,21 +182,6 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
169182
return os << boost::stacktrace::to_string(f);
170183
}
171184

172-
struct this_thread_frames {
173-
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT;
174-
BOOST_STACKTRACE_FUNCTION static std::size_t dump(const char* file) BOOST_NOEXCEPT;
175-
176-
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
177-
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t dump(platform_specific fd) BOOST_NOEXCEPT;
178-
#elif defined(BOOST_WINDOWS)
179-
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t dump(void* fd) BOOST_NOEXCEPT;
180-
#else
181-
// POSIX
182-
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t dump(int fd) BOOST_NOEXCEPT;
183-
#endif
184-
185-
};
186-
187185
}} // namespace boost::stacktrace
188186

189187
/// @cond
@@ -195,10 +193,8 @@ struct this_thread_frames {
195193
# include <boost/stacktrace/detail/frame_noop.ipp>
196194
# elif defined(BOOST_MSVC)
197195
# include <boost/stacktrace/detail/frame_msvc.ipp>
198-
# include <boost/stacktrace/detail/from_dump.ipp>
199196
# else
200197
# include <boost/stacktrace/detail/frame_unwind.ipp>
201-
# include <boost/stacktrace/detail/from_dump.ipp>
202198
# endif
203199
#endif
204200
/// @endcond

0 commit comments

Comments
 (0)