2

I run this code in Visual Studio 2013 (Debug config):

#include <thread>
#include <stdexcept>

void c() {
    /* breakpoint here*/ throw std::runtime_error("error"); 
}

void b() {
    c();
}

void a() {

    b();

}

int main(int argc, char** argv) {
    std::thread thr(a);

    if (thr.joinable()) thr.join();

    return 0;
}

The execution pauses at the breakpoint and I see the Call Stack:

> DemoProj.exe!c() Line 5   C++
DemoProj.exe!b() Line 10    C++
DemoProj.exe!a() Line 16    C++
[External Code] 

This is great! I can see exactly where I am in the course of the execution.

After that I go one step (F10) just to execute this exception throwing line. Of course, the exception gets thrown but now my Call Stack looks like this:

> msvcp120d.dll!_Call_func$catch$0() Line 30    C++
msvcr120d.dll!_CallSettingFrame() Line 51   Unknown
msvcr120d.dll!__CxxCallCatchBlock(_EXCEPTION_RECORD * pExcept) Line 1281    C++
ntdll.dll!RcConsolidateFrames() Unknown
msvcp120d.dll!_Call_func(void * _Data) Line 28  C++
msvcr120d.dll!_callthreadstartex() Line 376 C
msvcr120d.dll!_threadstartex(void * ptd) Line 359   C
kernel32.dll!BaseThreadInitThunk()  Unknown
ntdll.dll!RtlUserThreadStart()  Unknown

This renders my debugging useless. The line

/* breakpoint here*/ throw std::runtime_error("error"); 

is just here for this simple example. In real project I will not know where the code will break. And it would be of great help if Visual Studio could stop the execution on the exact line where the error occurred.

But instead, if an exception gets thrown anywhere outside my main thread, I only get these system calls and can never figure out what line in my code is causing the crash.

Any help?

I feel like this question is similar to this one. The idea there is to catch exceptions in side threads and pass them to the main thread so that the main thread can re-throw them. Isn't there some more elegant solution?

Community
  • 1
  • 1
AndroC
  • 4,758
  • 2
  • 46
  • 69
  • 2
    After the exception has already been caught, there is nothing you can do. The stack has already been unwound. You can however write your own exception class that dumps the stack (read StackWalk64) before actually throwing anything. https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.85).aspx – Sven Nilsson Jan 09 '17 at 11:08
  • 1
    The debugger normally stops on an unhandled exception. Trouble is, it is not unhandled. You are seeing the code that implements the requirement that an unhandled exception calls terminate(). It is an std::thread hazard. You'll have to debug this one with Debug > Exceptions > tick the Thrown checkbox for C++ exceptions. – Hans Passant Jan 09 '17 at 12:36
  • 1
    What do you want to see in the debugger? Given F10 steps over the line, and you're done. Are you asking how to catch the exeception on another thead? – doctorlove Jan 09 '17 at 13:12
  • The line where I throw the exception is just for this simple example. In real project I will not know where the code will break. And it would be of great help if Visual Studio could stop executing on the exact line where the error occurred. I will update the question. – AndroC Jan 09 '17 at 14:56
  • 1
    When I wrote my answer, I thought you want to log exceptions from worker threads. In VS2015 there is `ExceptionSetting` window that you can check various exceptions to always break when they get thrown. Also `__debugbreak()` compiler intrinsic in VC++ force debugger to break. – MRB Jan 09 '17 at 16:01

2 Answers2

3

it would be of great help if Visual Studio could stop the execution on the exact line where the error occurred.

Visual Studio has an option to automatically break when an exception is thrown. In Vs 2015 it's Debug -> Windows -> Exception Settings. Tick the C++ Exceptions checkbox under the Break When Thrown heading.

This is helpful for figuring out which code is throwing an exception. The drawback is that, if you have code that routinely throws and handles exceptions, you'll have a lot of undesired breaks in the debugger.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • Yes, this is the answer I was looking for. MRB already answered it in the comment. But I cannot accept comment as an answer... – AndroC Jan 10 '17 at 12:59
0

Why not use task based programming. Whenever you want to run code in separate thread, instead of creating and running a new thread just use already exist threads in a thread pool.

C++11 provide std::async that it's return type is a std::future:

std::future<void> future = std::async(std::launch::async, []{ a(); });

Every Exception thrown in other thread will be catch and store in std::future object and will throw if you call get on the std::future.

If you want to have stack trace you can write a custom exception that in it's ctor it use platform specific functions to capture stack function names and store them in itself.

MRB
  • 3,752
  • 4
  • 30
  • 44
  • I was not the one who downvoted, I hope an explanation will come for that downvote. – AndroC Jan 09 '17 at 12:16
  • @ancajic As I understand you want a way of exception logging in concurrent environment, and I think it's a way of doing that. – MRB Jan 09 '17 at 12:18