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).
This commit is contained in:
@@ -1012,25 +1012,37 @@ wxString wxAppTraitsBase::GetAssertStackTrace()
|
|||||||
#endif // !__WINDOWS__
|
#endif // !__WINDOWS__
|
||||||
|
|
||||||
|
|
||||||
wxString stackTrace;
|
|
||||||
|
|
||||||
class StackDump : public wxStackWalker
|
class StackDump : public wxStackWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StackDump() { }
|
StackDump() { m_numFrames = 0; }
|
||||||
|
|
||||||
const wxString& GetStackTrace() const { return m_stackTrace; }
|
const wxString& GetStackTrace() const { return m_stackTrace; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE
|
virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE
|
||||||
{
|
{
|
||||||
m_stackTrace << wxString::Format
|
// 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
|
||||||
wxT("[%02d] "),
|
// 15 pixel high characters it is still only 300 pixels...
|
||||||
wx_truncate_cast(int, frame.GetLevel())
|
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() )
|
if ( !name.empty() )
|
||||||
{
|
{
|
||||||
m_stackTrace << wxString::Format(wxT("%-40s"), name.c_str());
|
m_stackTrace << wxString::Format(wxT("%-40s"), name.c_str());
|
||||||
@@ -1053,22 +1065,12 @@ wxString wxAppTraitsBase::GetAssertStackTrace()
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
wxString m_stackTrace;
|
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;
|
StackDump dump;
|
||||||
dump.Walk(8, maxLines); // 8 is chosen to hide all OnAssert() calls
|
dump.Walk();
|
||||||
stackTrace = dump.GetStackTrace();
|
return dump.GetStackTrace();
|
||||||
|
|
||||||
const int count = stackTrace.Freq(wxT('\n'));
|
|
||||||
for ( int i = 0; i < count - maxLines; i++ )
|
|
||||||
stackTrace = stackTrace.BeforeLast(wxT('\n'));
|
|
||||||
|
|
||||||
return stackTrace;
|
|
||||||
#else // !wxDEBUG_LEVEL
|
#else // !wxDEBUG_LEVEL
|
||||||
// this function is still present for ABI-compatibility even in debug 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
|
// 0 build but is not used there and so can simply do nothing
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "wx/apptrait.h"
|
#include "wx/apptrait.h"
|
||||||
#include "wx/process.h"
|
#include "wx/process.h"
|
||||||
#include "wx/sysopt.h"
|
#include "wx/sysopt.h"
|
||||||
|
#include "wx/vector.h"
|
||||||
|
|
||||||
#include "wx/gtk/private/timer.h"
|
#include "wx/gtk/private/timer.h"
|
||||||
#include "wx/evtloop.h"
|
#include "wx/evtloop.h"
|
||||||
@@ -254,30 +255,68 @@ class StackDump : public wxStackWalker
|
|||||||
public:
|
public:
|
||||||
StackDump(GtkAssertDialog *dlg) { m_dlg=dlg; }
|
StackDump(GtkAssertDialog *dlg) { m_dlg=dlg; }
|
||||||
|
|
||||||
|
void ShowStackInDialog()
|
||||||
|
{
|
||||||
|
ProcessFrames(0);
|
||||||
|
|
||||||
|
for ( wxVector<Frame>::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:
|
protected:
|
||||||
virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE
|
virtual void OnStackFrame(const wxStackFrame& frame) wxOVERRIDE
|
||||||
{
|
{
|
||||||
wxString fncname = frame.GetName();
|
const wxString name = frame.GetName();
|
||||||
|
if ( name.StartsWith("wxOnAssert") )
|
||||||
// append this stack frame's info in the dialog
|
|
||||||
if (!frame.GetFileName().empty() || !fncname.empty())
|
|
||||||
{
|
{
|
||||||
gtk_assert_dialog_append_stack_frame(m_dlg,
|
// Ignore all frames until the wxOnAssert() one, just as we do in
|
||||||
fncname.utf8_str(),
|
// wxAppTraitsBase::GetAssertStackTrace().
|
||||||
frame.GetFileName().utf8_str(),
|
m_frames.clear();
|
||||||
frame.GetLine());
|
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:
|
private:
|
||||||
GtkAssertDialog *m_dlg;
|
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<Frame> m_frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void get_stackframe_callback(void* p)
|
static void get_stackframe_callback(void* p)
|
||||||
{
|
{
|
||||||
StackDump* dump = static_cast<StackDump*>(p);
|
StackDump* dump = static_cast<StackDump*>(p);
|
||||||
// skip over frames up to including wxOnAssert()
|
dump->ShowStackInDialog();
|
||||||
dump->ProcessFrames(6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxDEBUG_LEVEL && wxUSE_STACKWALKER
|
#endif // wxDEBUG_LEVEL && wxUSE_STACKWALKER
|
||||||
|
Reference in New Issue
Block a user