www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - proposal: better stack trace support could advantageously replace

Currently a number of functions in phobos have a syntax such as:
'T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)'
so as to show informative messages when an exception is raised, etc.

There's a number of issues with this:

1) impossible to have variadic arguments with an extra file/line parameters
at the end (unless one makes those file/line as compile time parameters but
that makes template code bloat), which would be very useful for debugging

2) the context is limited to the calling function (ie top-most stack frame

3) the code is more complex than needs to be, especially when we need to
forward those arguments (again, due to the stack trace being limited to
top-most frame), as every intermediate function is involved in passing
around those arguments, whereas ideally these should only occur in 1
location (eg, at the place responsible to handle an assert failure).
Furthermore, if we later want to add more information to the context (eg
__MODULE__,__FUNCTION__, __COLUMN__ or __ARGUMENTS__), we would have to
refactor a lot of code.

4) this is possibly inefficient, as we're passing around potentially more
parameters than needed.

What about the following instead:

A) implicit context parameters (eg: string file = __FILE__, size_t line =
__LINE__) are no longer needed

B) whenever a stack trace is requested (eg upon an assertion failure,
program crash or signal handler), call a unique getStackTrace function
(that doesn't use the GC). This allows to show full stack trace (more
depth), with potentially more info (eg showing module, function name,
stringified arguments, etc).

C) when an exception is thrown (which may be caught later), we need to save
the stack-trace as efficiently as possible (ie saving the stringified stack
trace would be wasteful). On possibility would be to store an array of
return addresses (given by C backtrace function), memoized using
std.function.memoize. Another would be using a trie data structure, with
the assumption that there's only a limited number of such execution paths
whose stacktrace will be requested; this should be very efficient

D) For a simple implementation, getStackTrace can be based on C functions
backtrace/backtrace_symbols but these are not very reliable depending on
compiler/operating system/compile options: inlining, off-by-1, missing
debug symbols, file base name but no full name, etc. There's
also __builtin_return_address and 'llvm.returnaddress' Intrinsics that
could be used.

So this could be improved with compiler support, introducing backtraceD /
backtrace_symbolsD (D's equivalent of the existing backtrace /
backtrace_symbols) that should work irrespective of OS/D
compiler/inlining/compiler flags. In particular, when the compiler inlines:
'main > funInlined> fun' to 'main > fun',
it should still be possible to keep track of the intermediate source level
function calls with proper book-keeping in the object file.
Aug 17 2013