From b7f1ac40f4321f1424ee744de0bb86cca2e405c1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 5 Jul 2015 18:33:49 +0200 Subject: [PATCH] Don't hard code the number of stack frames after wxOnAssert(). The number of frames between the code containing the assert and the code generating the stack trace is not the same under different platforms and so hardcoding 8 for it in wxAppTraitsBase::GetAssertStackTrace() worked for wxMSW but not e.g. wxGTK. Instead, just ignore all frames up to and including the one for wxOnAssert() itself. This makes the code work correctly on all platforms and it also won't need to be modified whenever any extra functions are added/removed (wxGTK-specific code in utilsgtk.cpp used wrong number of frames too, even though it was presumably correct once before). --- src/common/appbase.cpp | 46 ++++++++++++++++---------------- src/gtk/utilsgtk.cpp | 59 +++++++++++++++++++++++++++++++++++------- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 93a47aad1b..cfd8bd5c41 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -1012,25 +1012,37 @@ wxString wxAppTraitsBase::GetAssertStackTrace() #endif // !__WINDOWS__ - wxString stackTrace; - class StackDump : public wxStackWalker { public: - StackDump() { } + StackDump() { m_numFrames = 0; } const wxString& GetStackTrace() const { return m_stackTrace; } protected: virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE { - m_stackTrace << wxString::Format - ( - wxT("[%02d] "), - wx_truncate_cast(int, frame.GetLevel()) - ); + // don't show more than maxLines or we could get a dialog too tall + // to be shown on screen: 20 should be ok everywhere as even with + // 15 pixel high characters it is still only 300 pixels... + if ( m_numFrames++ > 20 ) + return; + + m_stackTrace << wxString::Format(wxT("[%02u] "), m_numFrames); + + const wxString name = frame.GetName(); + if ( name.StartsWith("wxOnAssert") ) + { + // Ignore all frames until the wxOnAssert() one, they are + // internal to wxWidgets and not interesting for the user + // (but notice that if we never find the wxOnAssert() frame, + // e.g. because we don't have symbol info at all, we would show + // everything which is better than not showing anything). + m_stackTrace.clear(); + m_numFrames = 0; + return; + } - wxString name = frame.GetName(); if ( !name.empty() ) { m_stackTrace << wxString::Format(wxT("%-40s"), name.c_str()); @@ -1053,22 +1065,12 @@ wxString wxAppTraitsBase::GetAssertStackTrace() private: wxString m_stackTrace; + unsigned m_numFrames; }; - // don't show more than maxLines or we could get a dialog too tall to be - // shown on screen: 20 should be ok everywhere as even with 15 pixel high - // characters it is still only 300 pixels... - static const int maxLines = 20; - StackDump dump; - dump.Walk(8, maxLines); // 8 is chosen to hide all OnAssert() calls - stackTrace = dump.GetStackTrace(); - - const int count = stackTrace.Freq(wxT('\n')); - for ( int i = 0; i < count - maxLines; i++ ) - stackTrace = stackTrace.BeforeLast(wxT('\n')); - - return stackTrace; + dump.Walk(); + return dump.GetStackTrace(); #else // !wxDEBUG_LEVEL // this function is still present for ABI-compatibility even in debug level // 0 build but is not used there and so can simply do nothing diff --git a/src/gtk/utilsgtk.cpp b/src/gtk/utilsgtk.cpp index d1603d7f1a..36c5013722 100644 --- a/src/gtk/utilsgtk.cpp +++ b/src/gtk/utilsgtk.cpp @@ -20,6 +20,7 @@ #include "wx/apptrait.h" #include "wx/process.h" #include "wx/sysopt.h" +#include "wx/vector.h" #include "wx/gtk/private/timer.h" #include "wx/evtloop.h" @@ -254,30 +255,68 @@ class StackDump : public wxStackWalker public: StackDump(GtkAssertDialog *dlg) { m_dlg=dlg; } + void ShowStackInDialog() + { + ProcessFrames(0); + + for ( wxVector::const_iterator it = m_frames.begin(); + it != m_frames.end(); + ++it ) + { + gtk_assert_dialog_append_stack_frame(m_dlg, + it->name.utf8_str(), + it->file.utf8_str(), + it->line); + } + + m_frames.clear(); + } + protected: virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE { - wxString fncname = frame.GetName(); - - // append this stack frame's info in the dialog - if (!frame.GetFileName().empty() || !fncname.empty()) + const wxString name = frame.GetName(); + if ( name.StartsWith("wxOnAssert") ) { - gtk_assert_dialog_append_stack_frame(m_dlg, - fncname.utf8_str(), - frame.GetFileName().utf8_str(), - frame.GetLine()); + // Ignore all frames until the wxOnAssert() one, just as we do in + // wxAppTraitsBase::GetAssertStackTrace(). + m_frames.clear(); + return; } + + // Also ignore frames which don't have neither the function name nor + // the file name, showing them in the dialog wouldn't provide any + // useful information. + if ( name.empty() && frame.GetFileName().empty() ) + return; + + m_frames.push_back(Frame(frame)); } private: GtkAssertDialog *m_dlg; + + struct Frame + { + explicit Frame(const wxStackFrame& f) + : name(f.GetName()), + file(f.GetFileName()), + line(f.GetLine()) + { + } + + wxString name; + wxString file; + int line; + }; + + wxVector m_frames; }; static void get_stackframe_callback(void* p) { StackDump* dump = static_cast(p); - // skip over frames up to including wxOnAssert() - dump->ProcessFrames(6); + dump->ShowStackInDialog(); } #endif // wxDEBUG_LEVEL && wxUSE_STACKWALKER