Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
c6e65641
Commit
c6e65641
authored
May 05, 2015
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve backtraces:
- Reduce noise. - Trace through async callbacks.
parent
0c0ed1d3
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
211 additions
and
34 deletions
+211
-34
rpc.c++
c++/src/capnp/rpc.c++
+5
-0
async-inl.h
c++/src/kj/async-inl.h
+79
-2
async.c++
c++/src/kj/async.c++
+7
-2
common.h
c++/src/kj/common.h
+6
-0
debug.c++
c++/src/kj/debug.c++
+2
-2
debug.h
c++/src/kj/debug.h
+1
-1
exception.c++
c++/src/kj/exception.c++
+86
-23
exception.h
c++/src/kj/exception.h
+24
-3
test.c++
c++/src/kj/test.c++
+1
-1
No files found.
c++/src/capnp/rpc.c++
View file @
c6e65641
...
@@ -116,6 +116,11 @@ void fromException(const kj::Exception& exception, rpc::Exception::Builder build
...
@@ -116,6 +116,11 @@ void fromException(const kj::Exception& exception, rpc::Exception::Builder build
// transmit stack traces?
// transmit stack traces?
builder
.
setReason
(
exception
.
getDescription
());
builder
.
setReason
(
exception
.
getDescription
());
builder
.
setType
(
static_cast
<
rpc
::
Exception
::
Type
>
(
exception
.
getType
()));
builder
.
setType
(
static_cast
<
rpc
::
Exception
::
Type
>
(
exception
.
getType
()));
if
(
exception
.
getType
()
==
kj
::
Exception
::
Type
::
FAILED
&&
!
exception
.
getDescription
().
startsWith
(
"remote exception:"
))
{
KJ_LOG
(
INFO
,
"returning failure over rpc"
,
exception
);
}
}
}
uint
exceptionSizeHint
(
const
kj
::
Exception
&
exception
)
{
uint
exceptionSizeHint
(
const
kj
::
Exception
&
exception
)
{
...
...
c++/src/kj/async-inl.h
View file @
c6e65641
...
@@ -246,9 +246,84 @@ private:
...
@@ -246,9 +246,84 @@ private:
// -------------------------------------------------------------------
// -------------------------------------------------------------------
class
PtmfHelper
{
// This class is a private helper for GetFunctorStartAddress. The class represents the internal
// representation of a pointer-to-member-function.
template
<
typename
...
ParamTypes
>
friend
struct
GetFunctorStartAddress
;
#if __GNUG__
void
*
ptr
;
ptrdiff_t
adj
;
// Layout of a pointer-to-member-function used by GCC and compatible compilers.
#else
#error "TODO(port): PTMF instruction address extraction"
#endif
#define BODY \
PtmfHelper result; \
static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \
memcpy(&result, &p, sizeof(result)); \
return result
template
<
typename
R
,
typename
C
,
typename
...
P
,
typename
F
>
static
PtmfHelper
from
(
F
p
)
{
BODY
;
}
// Create a PtmfHelper from some arbitrary pointer-to-member-function which is not
// overloaded nor a template. In this case the compiler is able to deduce the full function
// signature directly given the name since there is only one function with that name.
template
<
typename
R
,
typename
C
,
typename
...
P
>
static
PtmfHelper
from
(
R
(
C
::*
p
)(
NoInfer
<
P
>
...))
{
BODY
;
}
template
<
typename
R
,
typename
C
,
typename
...
P
>
static
PtmfHelper
from
(
R
(
C
::*
p
)(
NoInfer
<
P
>
...)
const
)
{
BODY
;
}
// Create a PtmfHelper from some poniter-to-member-function which is a template. In this case
// the function must match exactly the containing type C, return type R, and parameter types P...
// GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a
// guess at P. Luckily, if the function parameters are template parameters then it's not
// necessary to be precise about P.
#undef BODY
void
*
apply
(
void
*
obj
)
{
ptrdiff_t
voff
=
(
ptrdiff_t
)
ptr
;
if
(
voff
&
1
)
{
voff
&=
~
1
;
return
*
(
void
**
)(
*
(
char
**
)
obj
+
voff
);
}
else
{
return
ptr
;
}
}
};
template
<
typename
...
ParamTypes
>
struct
GetFunctorStartAddress
{
// Given a functor (any object defining operator()), return the start address of the function,
// suitable for passing to addr2line to obtain a source file/line for debugging purposes.
//
// This turns out to be incredibly hard to implement in the presence of overloaded or templated
// functors. Therefore, we impose these specific restrictions, specific to our use case:
// - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas
// anyway.)
// - The template parameters to GetFunctorStartAddress specify a hint as to the expected
// parameter types. If the functor is templated, its parameters must match exactly these types.
// (If it's not templated, ParamTypes are ignored.)
template
<
typename
Func
>
static
void
*
apply
(
Func
&&
func
)
{
typedef
decltype
(
func
(
instance
<
ParamTypes
>
()...))
ReturnType
;
return
PtmfHelper
::
from
<
ReturnType
,
Decay
<
Func
>
,
ParamTypes
...
>
(
&
Decay
<
Func
>::
operator
()).
apply
(
&
func
);
}
};
template
<>
struct
GetFunctorStartAddress
<
Void
&&>:
public
GetFunctorStartAddress
<>
{};
// Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function
// actually has no parameters.
class
TransformPromiseNodeBase
:
public
PromiseNode
{
class
TransformPromiseNodeBase
:
public
PromiseNode
{
public
:
public
:
TransformPromiseNodeBase
(
Own
<
PromiseNode
>&&
dependency
);
TransformPromiseNodeBase
(
Own
<
PromiseNode
>&&
dependency
,
void
*
continuationTracePtr
);
void
onReady
(
Event
&
event
)
noexcept
override
;
void
onReady
(
Event
&
event
)
noexcept
override
;
void
get
(
ExceptionOrValue
&
output
)
noexcept
override
;
void
get
(
ExceptionOrValue
&
output
)
noexcept
override
;
...
@@ -256,6 +331,7 @@ public:
...
@@ -256,6 +331,7 @@ public:
private
:
private
:
Own
<
PromiseNode
>
dependency
;
Own
<
PromiseNode
>
dependency
;
void
*
continuationTracePtr
;
void
dropDependency
();
void
dropDependency
();
void
getDepResult
(
ExceptionOrValue
&
output
);
void
getDepResult
(
ExceptionOrValue
&
output
);
...
@@ -273,7 +349,8 @@ class TransformPromiseNode final: public TransformPromiseNodeBase {
...
@@ -273,7 +349,8 @@ class TransformPromiseNode final: public TransformPromiseNodeBase {
public
:
public
:
TransformPromiseNode
(
Own
<
PromiseNode
>&&
dependency
,
Func
&&
func
,
ErrorFunc
&&
errorHandler
)
TransformPromiseNode
(
Own
<
PromiseNode
>&&
dependency
,
Func
&&
func
,
ErrorFunc
&&
errorHandler
)
:
TransformPromiseNodeBase
(
kj
::
mv
(
dependency
)),
:
TransformPromiseNodeBase
(
kj
::
mv
(
dependency
),
GetFunctorStartAddress
<
DepT
&&>::
apply
(
func
)),
func
(
kj
::
fwd
<
Func
>
(
func
)),
errorHandler
(
kj
::
fwd
<
ErrorFunc
>
(
errorHandler
))
{}
func
(
kj
::
fwd
<
Func
>
(
func
)),
errorHandler
(
kj
::
fwd
<
ErrorFunc
>
(
errorHandler
))
{}
~
TransformPromiseNode
()
noexcept
(
false
)
{
~
TransformPromiseNode
()
noexcept
(
false
)
{
...
...
c++/src/kj/async.c++
View file @
c6e65641
...
@@ -557,8 +557,9 @@ void AttachmentPromiseNodeBase::dropDependency() {
...
@@ -557,8 +557,9 @@ void AttachmentPromiseNodeBase::dropDependency() {
// -------------------------------------------------------------------
// -------------------------------------------------------------------
TransformPromiseNodeBase
::
TransformPromiseNodeBase
(
Own
<
PromiseNode
>&&
dependencyParam
)
TransformPromiseNodeBase
::
TransformPromiseNodeBase
(
:
dependency
(
kj
::
mv
(
dependencyParam
))
{
Own
<
PromiseNode
>&&
dependencyParam
,
void
*
continuationTracePtr
)
:
dependency
(
kj
::
mv
(
dependencyParam
)),
continuationTracePtr
(
continuationTracePtr
)
{
dependency
->
setSelfPointer
(
&
dependency
);
dependency
->
setSelfPointer
(
&
dependency
);
}
}
...
@@ -590,6 +591,10 @@ void TransformPromiseNodeBase::getDepResult(ExceptionOrValue& output) {
...
@@ -590,6 +591,10 @@ void TransformPromiseNodeBase::getDepResult(ExceptionOrValue& output) {
}))
{
}))
{
output
.
addException
(
kj
::
mv
(
*
exception
));
output
.
addException
(
kj
::
mv
(
*
exception
));
}
}
KJ_IF_MAYBE
(
e
,
output
.
exception
)
{
e
->
addTrace
(
continuationTracePtr
);
}
}
}
// -------------------------------------------------------------------
// -------------------------------------------------------------------
...
...
c++/src/kj/common.h
View file @
c6e65641
...
@@ -156,6 +156,12 @@ typedef unsigned char byte;
...
@@ -156,6 +156,12 @@ typedef unsigned char byte;
// Force a function to always be inlined. Apply only to the prototype, not to the definition.
// Force a function to always be inlined. Apply only to the prototype, not to the definition.
#endif
#endif
#if defined(_MSC_VER)
#define KJ_NOINLINE __declspec(noinline)
#else
#define KJ_NOINLINE __attribute__((noinline))
#endif
#if defined(_MSC_VER)
#if defined(_MSC_VER)
#define KJ_NORETURN(prototype) __declspec(noreturn) prototype
#define KJ_NORETURN(prototype) __declspec(noreturn) prototype
#define KJ_UNUSED
#define KJ_UNUSED
...
...
c++/src/kj/debug.c++
View file @
c6e65641
...
@@ -276,7 +276,7 @@ Debug::Fault::~Fault() noexcept(false) {
...
@@ -276,7 +276,7 @@ Debug::Fault::~Fault() noexcept(false) {
if
(
exception
!=
nullptr
)
{
if
(
exception
!=
nullptr
)
{
Exception
copy
=
mv
(
*
exception
);
Exception
copy
=
mv
(
*
exception
);
delete
exception
;
delete
exception
;
throwRecoverableException
(
mv
(
copy
));
throwRecoverableException
(
mv
(
copy
)
,
2
);
}
}
}
}
...
@@ -284,7 +284,7 @@ void Debug::Fault::fatal() {
...
@@ -284,7 +284,7 @@ void Debug::Fault::fatal() {
Exception
copy
=
mv
(
*
exception
);
Exception
copy
=
mv
(
*
exception
);
delete
exception
;
delete
exception
;
exception
=
nullptr
;
exception
=
nullptr
;
throwFatalException
(
mv
(
copy
));
throwFatalException
(
mv
(
copy
)
,
2
);
abort
();
abort
();
}
}
...
...
c++/src/kj/debug.h
View file @
c6e65641
...
@@ -301,7 +301,7 @@ public:
...
@@ -301,7 +301,7 @@ public:
const
char
*
condition
,
const
char
*
macroArgs
);
const
char
*
condition
,
const
char
*
macroArgs
);
~
Fault
()
noexcept
(
false
);
~
Fault
()
noexcept
(
false
);
KJ_NORETURN
(
void
fatal
());
KJ_NO
INLINE
KJ_NO
RETURN
(
void
fatal
());
// Throw the exception.
// Throw the exception.
private
:
private
:
...
...
c++/src/kj/exception.c++
View file @
c6e65641
...
@@ -55,15 +55,18 @@ StringPtr KJ_STRINGIFY(LogSeverity severity) {
...
@@ -55,15 +55,18 @@ StringPtr KJ_STRINGIFY(LogSeverity severity) {
return
SEVERITY_STRINGS
[
static_cast
<
uint
>
(
severity
)];
return
SEVERITY_STRINGS
[
static_cast
<
uint
>
(
severity
)];
}
}
ArrayPtr
<
void
*
const
>
getStackTrace
(
ArrayPtr
<
void
*>
space
)
{
ArrayPtr
<
void
*
const
>
getStackTrace
(
ArrayPtr
<
void
*>
space
,
uint
ignoreCount
)
{
#ifndef KJ_HAS_BACKTRACE
#ifndef KJ_HAS_BACKTRACE
return
nullptr
;
return
nullptr
;
#else
#else
return
space
.
slice
(
0
,
backtrace
(
space
.
begin
(),
space
.
size
()));
size_t
size
=
backtrace
(
space
.
begin
(),
space
.
size
());
return
space
.
slice
(
kj
::
min
(
ignoreCount
+
1
,
size
),
size
);
#endif
#endif
}
}
String
stringifyStackTrace
(
ArrayPtr
<
void
*
const
>
trace
)
{
String
stringifyStackTrace
(
ArrayPtr
<
void
*
const
>
trace
)
{
if
(
trace
.
size
()
==
0
)
return
nullptr
;
#if (__linux__ || __APPLE__) && !__ANDROID__ && defined(KJ_DEBUG)
#if (__linux__ || __APPLE__) && !__ANDROID__ && defined(KJ_DEBUG)
// We want to generate a human-readable stack trace.
// We want to generate a human-readable stack trace.
...
@@ -115,20 +118,22 @@ String stringifyStackTrace(ArrayPtr<void* const> trace) {
...
@@ -115,20 +118,22 @@ String stringifyStackTrace(ArrayPtr<void* const> trace) {
char
line
[
512
];
char
line
[
512
];
size_t
i
=
0
;
size_t
i
=
0
;
while
(
i
<
kj
::
size
(
lines
)
&&
fgets
(
line
,
sizeof
(
line
),
p
)
!=
nullptr
)
{
while
(
i
<
kj
::
size
(
lines
)
&&
fgets
(
line
,
sizeof
(
line
),
p
)
!=
nullptr
)
{
// Don't include exception-handling infrastructure in stack trace.
// Don't include exception-handling infrastructure
or promise infrastructure
in stack trace.
// addr2line output matches file names; atos output matches symbol names.
// addr2line output matches file names; atos output matches symbol names.
if
(
i
==
0
&&
if
(
strstr
(
line
,
"kj/common.c++"
)
!=
nullptr
||
(
strstr
(
line
,
"kj/common.c++"
)
!=
nullptr
||
strstr
(
line
,
"kj/exception."
)
!=
nullptr
||
strstr
(
line
,
"kj/exception."
)
!=
nullptr
||
strstr
(
line
,
"kj/debug."
)
!=
nullptr
||
strstr
(
line
,
"kj/debug."
)
!=
nullptr
||
strstr
(
line
,
"kj/async."
)
!=
nullptr
||
strstr
(
line
,
"kj::Exception"
)
!=
nullptr
||
strstr
(
line
,
"kj/async-prelude.h"
)
!=
nullptr
||
strstr
(
line
,
"kj::_::Debug"
)
!=
nullptr
))
{
strstr
(
line
,
"kj/async-inl.h"
)
!=
nullptr
||
strstr
(
line
,
"kj::Exception"
)
!=
nullptr
||
strstr
(
line
,
"kj::_::Debug"
)
!=
nullptr
)
{
continue
;
continue
;
}
}
size_t
len
=
strlen
(
line
);
size_t
len
=
strlen
(
line
);
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\n'
)
line
[
len
-
1
]
=
'\0'
;
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\n'
)
line
[
len
-
1
]
=
'\0'
;
lines
[
i
++
]
=
str
(
"
\n
"
,
trimSourceFilename
(
line
),
":
called
here"
);
lines
[
i
++
]
=
str
(
"
\n
"
,
trimSourceFilename
(
line
),
":
returning
here"
);
}
}
// Skip remaining input.
// Skip remaining input.
...
@@ -146,12 +151,9 @@ namespace {
...
@@ -146,12 +151,9 @@ namespace {
void
crashHandler
(
int
signo
,
siginfo_t
*
info
,
void
*
context
)
{
void
crashHandler
(
int
signo
,
siginfo_t
*
info
,
void
*
context
)
{
void
*
traceSpace
[
32
];
void
*
traceSpace
[
32
];
auto
trace
=
getStackTrace
(
traceSpace
);
if
(
trace
.
size
()
>=
3
)
{
// ignoreCount = 2 to ignore crashHandler() and signal trampoline.
// Remove getStackTrace(), crashHandler() and signal trampoline from trace.
auto
trace
=
getStackTrace
(
traceSpace
,
2
);
trace
=
trace
.
slice
(
3
,
trace
.
size
());
}
auto
message
=
kj
::
str
(
"*** Received signal #"
,
signo
,
": "
,
strsignal
(
signo
),
auto
message
=
kj
::
str
(
"*** Received signal #"
,
signo
,
": "
,
strsignal
(
signo
),
"
\n
stack: "
,
strArray
(
trace
,
" "
),
"
\n
stack: "
,
strArray
(
trace
,
" "
),
...
@@ -276,15 +278,12 @@ String KJ_STRINGIFY(const Exception& e) {
...
@@ -276,15 +278,12 @@ String KJ_STRINGIFY(const Exception& e) {
}
}
Exception
::
Exception
(
Type
type
,
const
char
*
file
,
int
line
,
String
description
)
noexcept
Exception
::
Exception
(
Type
type
,
const
char
*
file
,
int
line
,
String
description
)
noexcept
:
file
(
trimSourceFilename
(
file
).
cStr
()),
line
(
line
),
type
(
type
),
description
(
mv
(
description
))
{
:
file
(
trimSourceFilename
(
file
).
cStr
()),
line
(
line
),
type
(
type
),
description
(
mv
(
description
)),
traceCount
=
kj
::
getStackTrace
(
trace
).
size
();
traceCount
(
0
)
{}
}
Exception
::
Exception
(
Type
type
,
String
file
,
int
line
,
String
description
)
noexcept
Exception
::
Exception
(
Type
type
,
String
file
,
int
line
,
String
description
)
noexcept
:
ownFile
(
kj
::
mv
(
file
)),
file
(
trimSourceFilename
(
ownFile
).
cStr
()),
line
(
line
),
type
(
type
),
:
ownFile
(
kj
::
mv
(
file
)),
file
(
trimSourceFilename
(
ownFile
).
cStr
()),
line
(
line
),
type
(
type
),
description
(
mv
(
description
))
{
description
(
mv
(
description
)),
traceCount
(
0
)
{}
traceCount
=
kj
::
getStackTrace
(
trace
).
size
();
}
Exception
::
Exception
(
const
Exception
&
other
)
noexcept
Exception
::
Exception
(
const
Exception
&
other
)
noexcept
:
file
(
other
.
file
),
line
(
other
.
line
),
type
(
other
.
type
),
:
file
(
other
.
file
),
line
(
other
.
line
),
type
(
other
.
type
),
...
@@ -314,6 +313,64 @@ void Exception::wrapContext(const char* file, int line, String&& description) {
...
@@ -314,6 +313,64 @@ void Exception::wrapContext(const char* file, int line, String&& description) {
context
=
heap
<
Context
>
(
file
,
line
,
mv
(
description
),
mv
(
context
));
context
=
heap
<
Context
>
(
file
,
line
,
mv
(
description
),
mv
(
context
));
}
}
void
Exception
::
extendTrace
(
uint
ignoreCount
)
{
KJ_STACK_ARRAY
(
void
*
,
newTraceSpace
,
kj
::
size
(
trace
)
+
ignoreCount
+
1
,
sizeof
(
trace
)
/
sizeof
(
trace
[
0
])
+
8
,
128
);
auto
newTrace
=
kj
::
getStackTrace
(
newTraceSpace
,
ignoreCount
+
1
);
if
(
newTrace
.
size
()
>
ignoreCount
+
2
)
{
// Remove suffix that won't fit into our static-sized trace.
newTrace
=
newTrace
.
slice
(
0
,
kj
::
min
(
kj
::
size
(
trace
)
-
traceCount
,
newTrace
.
size
()));
// Copy the rest into our trace.
memcpy
(
trace
+
traceCount
,
newTrace
.
begin
(),
newTrace
.
asBytes
().
size
());
traceCount
+=
newTrace
.
size
();
}
}
void
Exception
::
truncateCommonTrace
()
{
if
(
traceCount
>
0
)
{
// Create a "reference" stack trace that is a little bit deeper than the one in the exception.
void
*
refTraceSpace
[
sizeof
(
this
->
trace
)
/
sizeof
(
this
->
trace
[
0
])
+
4
];
auto
refTrace
=
kj
::
getStackTrace
(
refTraceSpace
,
0
);
// We expect that the deepest frame in the exception's stack trace should be somewhere in our
// own trace, since our own trace has a deeper limit. Search for it.
for
(
uint
i
=
refTrace
.
size
();
i
>
0
;
i
--
)
{
if
(
refTrace
[
i
-
1
]
==
trace
[
traceCount
-
1
])
{
// See how many frames match.
for
(
uint
j
=
0
;
j
<
i
;
j
++
)
{
if
(
j
>=
traceCount
)
{
// We matched the whole trace, apparently?
traceCount
=
0
;
return
;
}
else
if
(
refTrace
[
i
-
j
-
1
]
!=
trace
[
traceCount
-
j
-
1
])
{
// Found mismatching entry.
// If we matched more than half of the reference trace, guess that this is in fact
// the prefix we're looking for.
if
(
j
>
refTrace
.
size
()
/
2
)
{
// Delete the matching suffix. Also delete one non-matched entry on the assumption
// that both traces contain that stack frame but are simply at different points in
// the function.
traceCount
-=
j
+
1
;
return
;
}
}
}
}
}
// No match. Ignore.
}
}
void
Exception
::
addTrace
(
void
*
ptr
)
{
if
(
traceCount
<
kj
::
size
(
trace
))
{
trace
[
traceCount
++
]
=
ptr
;
}
}
class
ExceptionImpl
:
public
Exception
,
public
std
::
exception
{
class
ExceptionImpl
:
public
Exception
,
public
std
::
exception
{
public
:
public
:
inline
ExceptionImpl
(
Exception
&&
other
)
:
Exception
(
mv
(
other
))
{}
inline
ExceptionImpl
(
Exception
&&
other
)
:
Exception
(
mv
(
other
))
{}
...
@@ -436,12 +493,14 @@ ExceptionCallback& getExceptionCallback() {
...
@@ -436,12 +493,14 @@ ExceptionCallback& getExceptionCallback() {
return
scoped
!=
nullptr
?
*
scoped
:
defaultCallback
;
return
scoped
!=
nullptr
?
*
scoped
:
defaultCallback
;
}
}
void
throwFatalException
(
kj
::
Exception
&&
exception
)
{
void
throwFatalException
(
kj
::
Exception
&&
exception
,
uint
ignoreCount
)
{
exception
.
extendTrace
(
ignoreCount
+
1
);
getExceptionCallback
().
onFatalException
(
kj
::
mv
(
exception
));
getExceptionCallback
().
onFatalException
(
kj
::
mv
(
exception
));
abort
();
abort
();
}
}
void
throwRecoverableException
(
kj
::
Exception
&&
exception
)
{
void
throwRecoverableException
(
kj
::
Exception
&&
exception
,
uint
ignoreCount
)
{
exception
.
extendTrace
(
ignoreCount
+
1
);
getExceptionCallback
().
onRecoverableException
(
kj
::
mv
(
exception
));
getExceptionCallback
().
onRecoverableException
(
kj
::
mv
(
exception
));
}
}
...
@@ -549,12 +608,16 @@ Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
...
@@ -549,12 +608,16 @@ Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
#if KJ_NO_EXCEPTIONS
#if KJ_NO_EXCEPTIONS
RecoverableExceptionCatcher
catcher
;
RecoverableExceptionCatcher
catcher
;
runnable
.
run
();
runnable
.
run
();
KJ_IF_MAYBE
(
e
,
catcher
.
caught
)
{
e
->
truncateCommonTrace
();
}
return
mv
(
catcher
.
caught
);
return
mv
(
catcher
.
caught
);
#else
#else
try
{
try
{
runnable
.
run
();
runnable
.
run
();
return
nullptr
;
return
nullptr
;
}
catch
(
Exception
&
e
)
{
}
catch
(
Exception
&
e
)
{
e
.
truncateCommonTrace
();
return
kj
::
mv
(
e
);
return
kj
::
mv
(
e
);
}
catch
(
std
::
bad_alloc
&
e
)
{
}
catch
(
std
::
bad_alloc
&
e
)
{
return
Exception
(
Exception
::
Type
::
OVERLOADED
,
return
Exception
(
Exception
::
Type
::
OVERLOADED
,
...
...
c++/src/kj/exception.h
View file @
c6e65641
...
@@ -107,6 +107,19 @@ public:
...
@@ -107,6 +107,19 @@ public:
// is expected that contexts will be added in reverse order as the exception passes up the
// is expected that contexts will be added in reverse order as the exception passes up the
// callback stack.
// callback stack.
KJ_NOINLINE
void
extendTrace
(
uint
ignoreCount
);
// Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
// frames (see `getStackTrace()` for discussion of `ignoreCount`).
KJ_NOINLINE
void
truncateCommonTrace
();
// Remove the part of the stack trace which the exception shares with the caller of this method.
// This is used by the async library to remove the async infrastructure from the stack trace
// before replacing it with the async trace.
void
addTrace
(
void
*
ptr
);
// Append the given pointer to the backtrace, if it is not already full. This is used by the
// async library to trace through the promise chain that led to the exception.
private
:
private
:
String
ownFile
;
String
ownFile
;
const
char
*
file
;
const
char
*
file
;
...
@@ -193,11 +206,11 @@ private:
...
@@ -193,11 +206,11 @@ private:
ExceptionCallback
&
getExceptionCallback
();
ExceptionCallback
&
getExceptionCallback
();
// Returns the current exception callback.
// Returns the current exception callback.
KJ_NO
RETURN
(
void
throwFatalException
(
kj
::
Exception
&&
exception
));
KJ_NO
INLINE
KJ_NORETURN
(
void
throwFatalException
(
kj
::
Exception
&&
exception
,
uint
ignoreCount
=
0
));
// Invoke the exception callback to throw the given fatal exception. If the exception callback
// Invoke the exception callback to throw the given fatal exception. If the exception callback
// returns, abort.
// returns, abort.
void
throwRecoverableException
(
kj
::
Exception
&&
exception
);
KJ_NOINLINE
void
throwRecoverableException
(
kj
::
Exception
&&
exception
,
uint
ignoreCount
=
0
);
// Invoke the exception acllback to throw the given recoverable exception. If the exception
// Invoke the exception acllback to throw the given recoverable exception. If the exception
// callback returns, return normally.
// callback returns, return normally.
...
@@ -293,10 +306,18 @@ void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
...
@@ -293,10 +306,18 @@ void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
// =======================================================================================
// =======================================================================================
ArrayPtr
<
void
*
const
>
getStackTrace
(
ArrayPtr
<
void
*>
space
);
KJ_NOINLINE
ArrayPtr
<
void
*
const
>
getStackTrace
(
ArrayPtr
<
void
*>
space
,
uint
ignoreCount
);
// Attempt to get the current stack trace, returning a list of pointers to instructions. The
// Attempt to get the current stack trace, returning a list of pointers to instructions. The
// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
// If the platform doesn't support stack traces, returns an empty array.
// If the platform doesn't support stack traces, returns an empty array.
//
// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
// off a prefix of the trace that is uninteresting to the developer because it's just locations
// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
// ignored entries will still waste space in the `space` array (and the returned array's `begin()`
// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
// since `getStackTrace()` needs to ignore its own internal frames).
String
stringifyStackTrace
(
ArrayPtr
<
void
*
const
>
);
String
stringifyStackTrace
(
ArrayPtr
<
void
*
const
>
);
// Convert the stack trace to a string with file names and line numbers. This may involve executing
// Convert the stack trace to a string with file names and line numbers. This may involve executing
...
...
c++/src/kj/test.c++
View file @
c6e65641
...
@@ -192,7 +192,7 @@ public:
...
@@ -192,7 +192,7 @@ public:
void
logMessage
(
LogSeverity
severity
,
const
char
*
file
,
int
line
,
int
contextDepth
,
void
logMessage
(
LogSeverity
severity
,
const
char
*
file
,
int
line
,
int
contextDepth
,
String
&&
text
)
override
{
String
&&
text
)
override
{
void
*
traceSpace
[
32
];
void
*
traceSpace
[
32
];
auto
trace
=
getStackTrace
(
traceSpace
);
auto
trace
=
getStackTrace
(
traceSpace
,
2
);
if
(
text
.
size
()
==
0
)
{
if
(
text
.
size
()
==
0
)
{
text
=
kj
::
heapString
(
"expectation failed"
);
text
=
kj
::
heapString
(
"expectation failed"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment