bombela / backward-cpp

A beautiful stack trace pretty printer for C++
MIT License
3.73k stars 471 forks source link

Fix printing stack trace under Windows. #218

Closed blacktea closed 3 years ago

blacktea commented 3 years ago

This MR fixes stack trace under Windows. For example run test_suicide test. Stack trace Before:

-- running test case: stackoverflow
Stack trace (most recent call last):
#10   Object "", at 00007FFCC4777C24, in BaseThreadInitThunk
#9    Object "", at 00007FFC9BC4542C, in register_onexit_function
#8    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread", line 210, in std::_Pad::_Call_func [00007FF62002065D]
        207:    static _Call_func_ret _STDCALL _Call_func(void *_Data)
        208:            {       // entry point for new thread
        209:            static_cast<_Pad *>(_Data)->_Go();
      > 210:            _Cnd_do_broadcast_at_thread_exit();
        211:            return (0);
        212:            }
#7    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread", line 233, in std::_LaunchPad<std::unique_ptr<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> >,std::default_delete<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> > > > >::_Go [00007FF620023B48]
        230:    virtual void _Go()
        231:            {       // run the thread function object
        232:            _Run(this);
      > 233:            }
        234:
        235: private:
        236:    template<size_t... _Idxs>
#6    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread", line 247, in std::_LaunchPad<std::unique_ptr<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> >,std::default_delete<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> > > > >::_Run [00007FF62002918A]
        244:            {       // construct local unique_ptr and call function object within
        245:            _Target _Local(_STD forward<_Target>(_Ln->_MyTarget));
        246:            _Ln->_Release();
      > 247:            _Execute(*_Local,
        248:                    make_integer_sequence<size_t,
        249:                            tuple_size<typename _Target::element_type>::value>());
        250:            }
#5    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread", line 241, in std::_LaunchPad<std::unique_ptr<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> >,std::default_delete<std::tuple<<lambda_2b1cf13a17ccfdae79537f653d35df7c> > > > >::_Execute<0> [00007FF62000DE8C]
        238:                    integer_sequence<size_t, _Idxs...>)
        239:            {       // invoke function object packed in tuple
        240:            _STD invoke(_STD move(_STD get<_Idxs>(_Tup))...);
      > 241:            }
        242:
        243:    static void _Run(_LaunchPad *_Ln) _NOEXCEPT     // enforces termination
        244:            {       // construct local unique_ptr and call function object within
#4    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits", line 1445, in std::invoke<<lambda_2b1cf13a17ccfdae79537f653d35df7c> > [00007FF620014150]
       1442:    {       // INVOKE a callable object
       1443:    return (_Invoker<_Callable, _Types...>::_Call(
       1444:            _STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...));
      >1445:    }
       1446:
       1447: template<class _Rx,
       1448:    bool = is_void<_Rx>::value>
#3    Source "c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits", line 1377, in std::_Invoker_functor::_Call<<lambda_2b1cf13a17ccfdae79537f653d35df7c> > [00007FF62000C1A0]
       1374:            {       // INVOKE a function object
       1375:            return (_STD forward<_Callable>(_Obj)(
       1376:                    _STD forward<_Types>(_Args)...));
      >1377:            }
       1378:    };
       1379:
       1380: template<class _Callable,
#2    Source "c:\dev\opensource\backward-cpp\backward.hpp", line 4292, in <lambda_2b1cf13a17ccfdae79537f653d35df7c>::operator() [00007FF62001DDAA]
       4289:             handle_stacktrace(skip_recs());
       4290:           }
       4291:           {
      >4292:             std::unique_lock<std::mutex> lk(mtx());
       4293:             crashed() = crash_status::ending;
       4294:           }
       4295:           cv().notify_one();
#1    Source "c:\dev\opensource\backward-cpp\backward.hpp", line 4436, in backward::SignalHandling::handle_stacktrace [00007FF62002F886]
       4433:     st.set_context(ctx());
       4434:     st.set_thread_handle(thread_handle());
       4435:     st.load_here(32 + skip_frames);
      >4436:     st.skip_n_firsts(skip_frames);
       4437:
       4438:     printer.address = true;
       4439:     printer.print(st, std::cerr);
#0    Source "c:\dev\opensource\backward-cpp\backward.hpp", line 1134, in backward::StackTraceImpl<backward::system_tag::windows_tag>::load_here [00007FF62002FF93]
       1131:       RtlCaptureContext(ctx_);
       1132:     }
       1133:
      >1134:     if (!thd_) {
       1135:       thd_ = GetCurrentThread();
       1136:     }
Exit code: 3221225725

There are no names of method.

After:

`-- running test case: stackoverflow
Stack trace (most recent call last):
#31   Source "c:\dev\opensource\backward-cpp\test\suicide.cpp", line 78, in bye_bye_stack [00E18FC1]
         76: // Darwin does not allow RLIMIT_STACK to be reduced
         77: #ifndef __APPLE__
      >  78: int bye_bye_stack(int i) { return bye_bye_stack(i + 1) + bye_bye_stack(i * 2); }
         79:
         80: TEST_SEGFAULT(stackoverflow) {
         81: SignalHandling sh;

 ...
#2    Source "c:\dev\opensource\backward-cpp\test\suicide.cpp", line 78, in bye_bye_stack [00E18FC1]
         76: // Darwin does not allow RLIMIT_STACK to be reduced
         77: #ifndef __APPLE__
      >  78: int bye_bye_stack(int i) { return bye_bye_stack(i + 1) + bye_bye_stack(i * 2); }
         79:
         80: TEST_SEGFAULT(stackoverflow) {
         81: SignalHandling sh;
#1    Source "c:\dev\opensource\backward-cpp\test\suicide.cpp", line 78, in bye_bye_stack [00E18FC1]
         76: // Darwin does not allow RLIMIT_STACK to be reduced
         77: #ifndef __APPLE__
      >  78: int bye_bye_stack(int i) { return bye_bye_stack(i + 1) + bye_bye_stack(i * 2); }
         79:
         81: SignalHandling sh;
         77: #ifndef __APPLE__
      >  78: int bye_bye_stack(int i) { return bye_bye_stack(i + 1) + bye_bye_stack(i * 2); }
         80: TEST_SEGFAULT(stackoverflow) {
         81: SignalHandling sh;
Exit code: 3221225725
-- test case success: stackoverflow`

Now we can see places of recursion (bye_bye_stack).

Reason: Context is set at https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L4432. But later context is rewritten in load_here method https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L1120.

It's a not good idea to override non-virtual method of the base class https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L1114, https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L752, https://isocpp.org/wiki/faq/strange-inheritance#redefining-nonvirtuals.

blacktea commented 3 years ago

Hi, @bombela, is there any wrongs with the MR? Should I provide more clarifications(examples or smth like that)?

bombela commented 3 years ago

Nothing wrong. I am just a lazy open source maintainer. You raise a good point on the override of non-virtual methods.