forked from leha-bot/cpp-stacktrace-proposal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstacktrace.html
More file actions
237 lines (185 loc) · 12.4 KB
/
Copy pathstacktrace.html
File metadata and controls
237 lines (185 loc) · 12.4 KB
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<title>A Proposal to add stack trace library</title>
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
.addition { color: green; }
.right { float:right; }
.changed-deleted { background-color: #CFF0FC ; text-decoration: line-through; display: none; }
.addition.changed-deleted { color: green; background-color: #CFF0FC ; text-decoration: line-through; text-decoration: black double line-through; display: none; }
.changed-added { background-color: #CFF0FC ;}
.notes { background-color: #80D080 ;}
pre { line-height: 1.2; font-size: 10pt; margin-top: 25px; }
.desc { margin-left: 35px; margin-top: 10px; padding:0; white-space: normal; }
body {max-width: 1024px; margin-left: 25px;}
.cppkeyword { color: blue; }
.cppcomment { color: green; }
.cppcomment > .cppkeyword{ color: green; }
.cpptext { color: #2E8B57; }
</style>
</head>
<body bgcolor="#ffffff">
<address>Document number: D0881R0</address>
<address>Project: Programming Language C++</address>
<address>Audience: Library Evolution</address>
<address> </address>
<address>Alexey Gorgurov <<a href="mailto:leha-bot@yandex.ru">leha-bot@yandex.ru</a>>, <<a href="mailto:no-vista@yandex.ru">no-vista@yandex.ru</a>></address>
<address>Antony Polukhin <<a href="mailto:antoshkka@gmail.com">antoshkka@gmail.com</a>>, <<a href="mailto:antoshkka@yandex-team.ru">antoshkka@yandex-team.ru</a>></address>
<address> </address>
<address>Date: 2018-02-09</address>
<h1>A Proposal to add stack trace library</h1>
<!--p class='notes'>Green lines are notes for the <b>editor</b> or for the <b>SG14</b> that must not be treated as part of the wording.</p-->
<h2>I. Motivation</h2>
<p>In the current working draft [<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf">N4713</a>] there is no way to get,store and decode the current call sequence.
Such call sequences are useful for debugging and post mortem debugging. They are popular in other programming languages (like Java, C#, Python).</p>
<p>Pretty often assertions can't describe the whole picture of a bug and do not provide enough information to locate the problem.
For example, you can see the following message on out-of-range access:</p>
<pre>
boost/array.hpp:123: T& boost::array<T, N>::operator[](boost::array<T, N>::size_type): Assertion '(i < N)&&("out of range")' failed.
Aborted (core dumped)</pre>
<p>That's not enough information in the assert message to locate the problem without debugger.</p>
<p>This paper proposes classes that could simplify debugging and may change the assertion meassage into the following:</p>
<pre>
Expression 'i < N' is false in function 'T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul; boost::array<T, N>::reference = int&; boost::array<T, N>::size_type = long unsigned int]': out of range.
Backtrace:
0# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long) at ../example/assert_handler.cpp:39
1# boost::array<int, 5ul>::operator[](unsigned long) at ../../../boost/array.hpp:124
2# bar(int) at ../example/assert_handler.cpp:17
3# foo(int) at ../example/assert_handler.cpp:25
4# bar(int) at ../example/assert_handler.cpp:17
5# foo(int) at ../example/assert_handler.cpp:25
6# main at ../example/assert_handler.cpp:54
7# 0x00007F991FD69F45 in /lib/x86_64-linux-gnu/libc.so.6
8# 0x0000000000401139
</pre>
<h2>II. Impact on the Standard</h2>
<p>This proposal is a pure library extension and it does not break the existing code and does not degrade performance.
It does not require any changes in the core language and could be implemented in the standard C++.</p>
<h2>III. Design Decisions</h2>
<p>The design is based on the Boost.Stacktrace library, a popular library that does not depend on any non-standard library components.</p>
<p><b>Note about signal safety:</b> this proposal does not attempt to provide a signal-safe solution for capturing and decoding stacktraces.
Such functionality currently is not implementable on some of the popular platforms. However, the paper attempts to provide extendable solution, that may be made sygnal safe some day.</p>
<p><b>Note on performance:</b> during Boost.Stacktrace development phase many users requested a fast way to store stack trace, without decoding the function names. This functionality is preserved in the paper.</p>
<h2>IV. Proposed Interface</h2>
<h3>Header <stacktrace></h3>
<pre>
namespace std {
class stack_frame {
public:
using native_frame_ptr_t = <i>unspecified</i>;
// construct/copy/destruct
constexpr stack_frame() noexcept;
constexpr stack_frame(const stack_frame&) noexcept = default;
constexpr stack_frame& operator=(const stack_frame&) = default;
explicit stack_frame(native_frame_ptr_t f) noexcept;
template<typename T> explicit stack_frame(T* address) noexcept;
constexpr native_frame_ptr_t address() const noexcept;
constexpr bool empty() const noexcept;
strong_ordering operator <=>(const stack_frame& rhs) = default;
// functions that do decoding
string name() const;
string source_file() const;
size_t source_line() const;
private:
native_frame_ptr_t data; // exposiotion only
};
template<typename Allocator>
class basic_stacktrace {
public:
using value_type = stack_frame;
using const_reference = const value_type &;
using size_type = <i>implementation-defined</i>;
using const_iterator = <i>implementation-defined</i>;
using allocaotr_type = Allocator;
// functions that capture current call sequence without decoding it
basic_stacktrace() noexcept;
explicit basic_stacktrace(const allocator_type& a) noexcept;
basic_stacktrace(size_type skip, size_type max_depth, const allocator_type& a = allocator_type()) noexcept;
// construct/copy/destruct
basic_stacktrace(const basic_stacktrace &);
basic_stacktrace(basic_stacktrace &&) noexcept;
basic_stacktrace & operator=(const basic_stacktrace &);
basic_stacktrace & operator=(basic_stacktrace &&);
~basic_stacktrace();
// public member functions
size_type size() const noexcept;
const_reference operator[](size_type ) const noexcept;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
explicit operator bool() const noexcept;
template <typename Allocator2>
strong_ordering operator <=>(const basic_stacktrace< Allocator2 >& rhs) = default;
private:
vector<value_type> stack_frames; // exposition only
};
// This is the alias to use unless you'd like to provide a specific allocator to basic_stacktrace.
using stacktrace = basic_stacktrace<allocator<stack_frame>>;
// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
template<typename CharT, typename TraitsT, typename Allocator>
basic_ostream< CharT, TraitsT > & operator<<(basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt);
// Outputs frame in a human readable format to string; unsafe to use in async handlers.
string to_string(const stack_frame& f);
// Outputs frame in a human readable format to output stream; unsafe to use in async handlers.
template<typename CharT, typename TraitsT>
basic_ostream< CharT, TraitsT >& operator<<(basic_ostream<CharT, TraitsT>& os, const stack_frame& f);
}
</pre>
<h3><code>stack_frame</code> constructors</h3>
<pre>stack_frame() noexcept;</pre>
<div class="desc">Constructs stack_frame that references NULL address. Calls to <code>source_file()</code> and <code>source_line()</code> will return empty string. Calls to <code>source_line()</code> will return 0.</div>
<pre>explicit stack_frame(native_frame_ptr_t addr) noexcept;
template<typename T> explicit stack_frame(T * addr) noexcept;</pre>
<div class="desc">Constructs stack_frame that references addr and could later generate information about that address using platform specific features.</div>
<h3><code>stack_frame</code> member functions</h3>
<pre>std::string name() const;</pre>
<div class="desc">Returns platform specific name of the stack_frame (function name in a human readable form). Throws std::bad_alloc if not enough memory to construct resulting string.</div>
<pre>constexpr native_frame_ptr_t address() const noexcept;</pre>
<div class="desc">Returns address of the stack_frame.</div>
<pre>std::string source_file() const;</pre>
<div class="desc">Returns path to the source file, where the function of the frame is defined. Returns empty string if this->source_line() == 0. Throws std::bad_alloc if not enough memory to construct resulting string.</div>
<pre>std::string source_line() const;</pre>
<div class="desc">Returns code line in the source line, where the function of the frame is defined. Throws std::bad_alloc if not enough memory to construct resulting string.</div>
<pre>constexpr bool empty() const;</pre>
<div class="desc">Checks that stack_frame is not references NULL address.</div>
<h3><code>basic_stacktrace</code> constructors</h3>
<pre>basic_stacktrace() noexcept;
explicit basic_stacktrace(const allocator_type & a) noexcept;</pre>
<div class="desc">Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.</div>
<div class="desc">Any exception raised during this operation is
silently ignored. In case of exception <code>(bool)*this</code> is <code>false</code></div>
<pre>basic_stacktrace(size_type skip, size_type max_depth, const allocator_type& a = allocator_type()) noexcept;</pre>
<div class="desc">Stores [skip; skip + max_depth) of the current function call sequence inside *this without any decoding or any heavy platform specific operations.</div>
<div class="desc">Any exception raised during this operation is
silently ignored. In case of exception <code>(bool)*this</code> is <code>false</code></div>
<h3><code>basic_stacktrace</code> member functions</h3>
<pre>const_reference operator[](size_type frame_no) const noexcept;</pre>
<div class="desc">Returns frame that references the actual frame info, stored inside *this.</div>
<div class="desc">Parameters: <code>frame_no</code> - zero-based index of frame to return. 0 is the function index where stacktrace was constructed and index close to this->size() contains function main().</div>
<pre>explicit operator bool() const noexcept;</pre>
<div class="desc">Allows to check that stack trace capturing was successful.</div>
<h2>V. Feature-testing macro</h2>
<p>For the purposes of SG10 we recommend the feature-testing macro name <code>__cpp_lib_stacktrace</code>.</p>
<script type="text/javascript">
function colorize_texts(texts) {
for (var i = 0; i < texts.length; ++i) {
var text = texts[i].innerHTML;
text = text.replace(/namespace|enum|void|constexpr|extern|noexcept|bool|template|class |struct|auto|const |typename|explicit|public|private|#include|inline|typedef|static_assert|static_cast|static/g,"<span class='cppkeyword'>$&<\/span>");
text = text.replace(/\/\/[\s\S]+?\n/g,"<span class='cppcomment'>$&<\/span>");
texts[i].innerHTML = text;
}
}
colorize_texts(document.getElementsByTagName("pre"));
colorize_texts(document.getElementsByTagName("code"));
var show = false;
function show_hide_deleted() {
var to_change = document.getElementsByClassName('changed-deleted');
for (var i = 0; i < to_change.length; ++i) {
to_change[i].style.display = (show ? 'block' : 'none');
}
show = !show;
}
show_hide_deleted()
</script>
</body></html>