<p>Having done my type checker, I'm thinking on targetting C++. How can I efficiently add debugging information to thrown exceptions?</p>
<p>Similiar to JavaScript, you can throw anything. <code>Error</code>, when created, should have its call stack information based from where its constructor was invoked. <code>Error</code>s may be created and thrown indirectly, like:</p>
<pre><code>const e = new Error
throw e
</code></pre>
<p>Basically what I thought is that I can have a global, program-static stack, in the systems language side, holding such debug information, so it'd look like:</p>
<pre><code>callStackDebug = [
    '[top-level] at index.vs:1',
    'f() at index.vs:3',
]
</code></pre>
<p>For this example:</p>
<pre><code>f()
function f(): void {
    throw new Error('Message')
}
</code></pre>
<p>Then you get something like:</p>
<blockquote>
<p>Error: Message</p>
<ul>
<li>at <code>f()</code> at index.vs:3</li>
<li>at [top-level] at index.vs:1</li>
</ul>
</blockquote>
<p>However, I'm worried that this program-static debug information stack may not work for asynchronous functions or concurrent code. It may also be problematic in case code suspends due to a <code>throw</code> and an exception handler catches it, leading to wrong information:</p>
<pre><code>try {
    // ...
} catch (e: RangeError) {
    // ...
}
// debug information can be incorrect now due to call depth?
</code></pre>
<p>Considering I'm going to target C++, I ask, how can I overcome this?</p>

<exceptions><code-generation>
Modifying call stack locations for C++ exceptions
<p>Conceptually, the call stack information you want already lives in the call stack itself- the return addresses correspond to the source positions immediately after each active call.</p>
<p>This still applies to asynchronous and concurrent code: each individual task or thread gets its own stack or some equivalent. For instance, when using native threads, there will be multiple native call stacks, while async/await-style tasks tend to have some representation of what to do on completion, which typically is (or includes) their awaiter.</p>
<p>If you're using native threads, you can walk the stack to collect a stack trace like this in various platform-specific ways. There are libraries like Boost's stacktrace, libunwind, etc. These typically use native debug info to map return addresses to source positions, so C++ <code>#line</code> directives may be useful here, though this may depend on your C++ compiler. The main advantage of this approach is that you have just one &quot;source of truth&quot; about the current stack trace- the stack itself.</p>
<p>You can also maintain a data structure like your global <code>callStackDebug</code>, as long as you keep a separate copy for each thread/task. This adds some additional pervasive overhead to call/return and try/catch, but it is also doable when targeting C++, as long as you can generate the appropriate fixup logic for each of those events. For instance, your try/catch example would need to truncate the debug stack in the catch block back to what it was on entry to the try block.</p>

CC BY-SA 4.0
2023-06-28T16:23:03.337Z
2023-06-28T16:23:03.337Z
rpjohnst
CC BY-SA 4.0
2023-06-28T17:35:33.060Z
I thought that `#line` directive was only supported in C, interesting! I never used much C/C++, so I played with `#line` now and am wondering why is there no full call stack? Is it possible to get the full call stack when creating an exception? https://www.sololearn.com/compiler-playground/cC3U2cqWAbIS
Hydroper
CC BY-SA 4.0
2023-06-28T17:42:06.920Z
I don't believe assert typically includes a call stack in C or C++- the standard only requires it to include the current source position. Exceptions don't typically include the call stack either; you'll need to collect it yourself using something like libunwind or C++23 <stacktrace>.
rpjohnst
# Modifying call stack locations for C++ exceptions
Posted by: username_0 on 2023-06-28
Having done my type checker, I'm thinking on targetting C++. How can I efficiently add debugging information to thrown exceptions?
Similiar to JavaScript, you can throw anything. Error, when created, should have its call stack information based from where its constructor was invoked. Errors may be created and thrown indirectly, like:
const e = new Error
throw e

Basically what I thought is that I can have a global, program-static stack, in the systems language side, holding such debug information, so it'd look like:
callStackDebug = [
    '[top-level] at index.vs:1',
    'f() at index.vs:3',
]

For this example:
f()
function f(): void {
    throw new Error('Message')
}

Then you get something like:

Error: Message

at f() at index.vs:3
at [top-level] at index.vs:1


However, I'm worried that this program-static debug information stack may not work for asynchronous functions or concurrent code. It may also be problematic in case code suspends due to a throw and an exception handler catches it, leading to wrong information:
try {
    // ...
} catch (e: RangeError) {
    // ...
}
// debug information can be incorrect now due to call depth?

Considering I'm going to target C++, I ask, how can I overcome this?
**Tags:** exceptions code-generation
---
## 1 answers
### Answer by username_1 on 2023-06-28. Score: 4
Conceptually, the call stack information you want already lives in the call stack itself- the return addresses correspond to the source positions immediately after each active call.

This still applies to asynchronous and concurrent code: each individual task or thread gets its own stack or some equivalent. For instance, when using native threads, there will be multiple native call stacks, while async/await-style tasks tend to have some representation of what to do on completion, which typically is (or includes) their awaiter.

If you're using native threads, you can walk the stack to collect a stack trace like this in various platform-specific ways. There are libraries like Boost's stacktrace, libunwind, etc. These typically use native debug info to map return addresses to source positions, so C++ `#line` directives may be useful here, though this may depend on your C++ compiler. The main advantage of this approach is that you have just one "source of truth" about the current stack trace- the stack itself.

You can also maintain a data structure like your global `callStackDebug`, as long as you keep a separate copy for each thread/task. This adds some additional pervasive overhead to call/return and try/catch, but it is also doable when targeting C++, as long as you can generate the appropriate fixup logic for each of those events. For instance, your try/catch example would need to truncate the debug stack in the catch block back to what it was on entry to the try block.
> **Comments:**
> **username_0** (2023-06-28): I thought that `#line` directive was only supported in C, interesting! I never used much C/C++, so I played with `#line` now and am wondering why is there no full call stack? Is it possible to get the full call stack when creating an exception? https://www.sololearn.com/compiler-playground/cC3U2cqWAbIS  
> **username_1** (2023-06-28): I don't believe assert typically includes a call stack in C or C++- the standard only requires it to include the current source position. Exceptions don't typically include the call stack either; you'll need to collect it yourself using something like libunwind or C++23 <stacktrace>.  
---
