jeremy-rifkin / cpptrace

Simple, portable, and self-contained stacktrace library for C++11 and newer
MIT License
621 stars 64 forks source link

why can't get full stack in windows #120

Closed CoolCaicaixian closed 3 months ago

CoolCaicaixian commented 4 months ago
截屏2024-05-08 11 19 50
CoolCaicaixian commented 4 months ago

I can't get the stack of this ddd() function

CoolCaicaixian commented 4 months ago

` void ddd(){ printf("dddddd...\n"); std::vector vec; vec.resize(10); printf("%d\n", vec.at(10)); printf("%d\n", vec[10]); }

// The function we want to execute on the new thread. void CrashThreadFunction() { std::cout << "Crash Thread Function started..." << std::endl; std::cout << "Now we will crash..." << std::endl;

try
{
    ddd();
    throw std::out_of_range("Something went wrong!");
}
catch(const std::exception& e)
{
    std::cerr << e.what() << '\n';
    cpptrace::generate_trace().print();
}

} `

jeremy-rifkin commented 4 months ago

Hi, Unfortunately by the time the body of the catch runs, unwinding has already taken place and the stack has been lost - stack traces must be generated at the point you want a trace to. Generally for exceptions what you'd want to do is throw a cpptrace traced exception object, like cpptrace::runtime_error, however in the case of code you don't control such as std:: code the best that can be done is CPPTRACE_WRAP(vec.at(10)) (which will intercept the std::out_of_range exception and collect a stack trace before unwinding to your catch). More info here.

CoolCaicaixian commented 4 months ago

您好, 不幸的是,当运行主体时catch,展开已经发生并且堆栈已丢失 - 堆栈跟踪必须在您想要跟踪的点生成。 一般来说,对于异常,您想要做的是抛出一个 cpptrace 跟踪的异常对象,例如cpptrace::runtime_error,但是对于您无法控制的代码(例如代码),std::最好的做法是CPPTRACE_WRAP(vec.at(10))(它将拦截std::out_of_range异常并收集展开到您的 ) 之前的堆栈跟踪catch。更多信息请点击此处

Thank you, I will try the way you say it. One more question, does this library conflict with asan?

CoolCaicaixian commented 4 months ago

Hi, Unfortunately by the time the body of the catch runs, unwinding has already taken place and the stack has been lost - stack traces must be generated at the point you want a trace to. Generally for exceptions what you'd want to do is throw a cpptrace traced exception object, like cpptrace::runtime_error, however in the case of code you don't control such as std:: code the best that can be done is CPPTRACE_WRAP(vec.at(10)) (which will intercept the std::out_of_range exception and collect a stack trace before unwinding to your catch). More info here.

Is there any other way, because I may need to reference other people's libraries and cannot modify their code, I just need to get the stack

CoolCaicaixian commented 4 months ago
截屏2024-05-08 13 59 12

Unfortunately, this doesn't seem to work

CoolCaicaixian commented 4 months ago

![Uploading 截屏2024-05-08 14.56.44.png…]() still useless

CoolCaicaixian commented 4 months ago

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo){

// CreateMiniDump(ExceptionInfo);
PrintStackTrace2();

return EXCEPTION_EXECUTE_HANDLER;

}

CoolCaicaixian commented 4 months ago

长 WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo){

// CreateMiniDump(ExceptionInfo);
PrintStackTrace2();

return EXCEPTION_EXECUTE_HANDLER;

}

This will print the stack normally

jeremy-rifkin commented 4 months ago

One more question, does this library conflict with asan?

Nope, should be fine

Is there any other way, because I may need to reference other people's libraries and cannot modify their code, I just need to get the stack

No, the language doesn't provide any means for you to hook exceptions other people throw. Unfortuantely.

Unfortunately, this doesn't seem to work

Could you send a minimal reproducible example?

jeremy-rifkin commented 4 months ago

As a demo, it does work for me: https://godbolt.org/z/coxhcz5ae

image

CoolCaicaixian commented 4 months ago

https://godbolt.org/z/coxhcz5ae

when I do 'catch(cpptrace::exception& e)', it took effect.

CoolCaicaixian commented 4 months ago

There are exceptions that are being caught, and it seems that the stack can only reach the first catch, but I didn't find relevant information on the Internet. Can you help provide it?

CoolCaicaixian commented 4 months ago

Is there a way to catch all threads 'stacks for uncaught exceptions? Use your library, or other tool

CoolCaicaixian commented 4 months ago

As a demo, it does work for me: https://godbolt.org/z/coxhcz5ae

image

u do not use MSVC,but gcc

CoolCaicaixian commented 4 months ago

企业微信截图_e80a26b1-dcb0-41f6-b25b-ff2de735a293 Why can vs catch the stack of child thread exceptions

jeremy-rifkin commented 4 months ago

Is there a way to catch all threads 'stacks for uncaught exceptions? Use your library, or other tool

If you just need the stack during local debugging then a debugger is the way to go

CoolCaicaixian commented 4 months ago

Is there a way to catch all threads 'stacks for uncaught exceptions? Use your library, or other tool

If you just need the stack during local debugging then a debugger is the way to go

Unfortunately, I need to add exception stack information to my automated tests

jeremy-rifkin commented 4 months ago

u do not use MSVC,but gcc

I tested with msvc and it worked for me

image

Unfortunately, I need to add exception stack information to my automated tests

Unfortunately the language does not provide any means to collect information on where stacktraces are thrown, unless you collect it yourself (as cpptrace exceptions do).

CoolCaicaixian commented 4 months ago

你不使用MSVC,而是使用gcc

我用 msvc 进行了测试,它对我有用

图像

不幸的是,我需要将异常堆栈信息添加到我的自动化测试中

不幸的是,该语言没有提供任何方法来收集有关堆栈跟踪抛出位置的信息,除非您自己收集它(如 cpptrace 异常所做的那样)。

I'm sorry to trouble you to go to windows to operate it!

CoolCaicaixian commented 4 months ago

Eventually I found a way to get the exception stack in the child thread. Don't handle exceptions.

template<typename Func, typename... Args>
auto WrapTask(std::shared_ptr<std::promise<typename std::result_of<Func(Args...)>::type>> promise, Func&& func, Args&&... args) 
-> std::function<void()> 
{
    return [p = std::move(promise), f = std::forward<Func>(func), args...]() mutable {
          std::set_terminate(PrintStackTrace2);
          if constexpr(std::is_same<typename std::result_of<Func(Args...)>::type, void>::value) {
              f(std::forward<Args>(args)...);
              p->set_value();
          } else {
              p->set_value(f(std::forward<Args>(args)...));
          }
    };
}

class IThreadCallback {

};

class MultiThreadPool
{
    using Task = std::function<void()>;

public:
    MultiThreadPool();
    ~MultiThreadPool();

    void startThread(int maxThreadNum, IThreadCallback *callback);
    void stopThread();

    template<class Func, class... Args>
    auto commitTask(Func&& func, Args&&... args) {
        using return_type = typename std::result_of<Func(Args...)>::type;

        auto promise = std::make_shared<std::promise<return_type>>();
        std::future<return_type> res = promise->get_future();

        auto task = WrapTask(promise, std::forward<Func>(func), std::forward<Args>(args)...);

        {
            std::unique_lock<std::mutex> lock(m_lock);

            if(m_stopped)
                throw std::runtime_error("enqueue on stopped ThreadPool");

            m_tasks.emplace(task);
        }
        m_cv.notify_one();
        return res;
    }

protected:
    int m_maxThreadNum = 0;
    std::vector<std::thread> m_threads;
    // 任务队列
    std::queue<Task> m_tasks;
    // 同步
    std::mutex m_lock;
    // 条件阻塞
    std::condition_variable m_cv;
    // 是否关闭提交
    std::atomic<bool> m_stopped;

    IThreadCallback *m_threadCallback = nullptr;
};
jeremy-rifkin commented 3 months ago

I'm glad you found a solution that works for you :)