DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg ) { // Recursion guard: Allow at least one recursive call. This is useful because sometimes // we get meaningless assertions while unwinding stack traces after exceptions have occurred. RecursionGuard guard( s_assert_guard ); if (guard.Counter > 2) { return wxTrap(); } // wxWidgets doesn't come with debug builds on some Linux distros, and other distros make // it difficult to use the debug build (compilation failures). To handle these I've had to // bypass the internal wxWidgets assertion handler entirely, since it may not exist even if // PCSX2 itself is compiled in debug mode (assertions enabled). bool trapit; if( pxDoAssert == NULL ) { // Note: Format uses MSVC's syntax for output window hotlinking. trapit = pxAssertImpl_LogIt( origin, msg ); } else { trapit = pxDoAssert( origin, msg ); } if( trapit ) { pxTrap(); } }
// this function is called when an assert fails void wxOnAssert(const wxChar *szFile, int nLine, const wxChar *szCond, const wxChar *szMsg) { // FIXME MT-unsafe static bool s_bInAssert = false; if ( s_bInAssert ) { // He-e-e-e-elp!! we're trapped in endless loop wxTrap(); s_bInAssert = false; return; } s_bInAssert = true; if ( !wxTheApp ) { // by default, show the assert dialog box -- we can't customize this // behaviour ShowAssertDialog(szFile, nLine, szCond, szMsg); } else { // let the app process it as it wants wxTheApp->OnAssert(szFile, nLine, szCond, szMsg); } s_bInAssert = false; }
void CardViewer::onPaint(wxPaintEvent&) { #ifdef _DEBUG // we don't want recursion if (inOnPaint()) { wxTrap(); } WITH_DYNAMIC_ARG(inOnPaint, true); #endif wxSize cs = GetClientSize(); if (!buffer.Ok() || buffer.GetWidth() != cs.GetWidth() || buffer.GetHeight() != cs.GetHeight()) { buffer = Bitmap(cs.GetWidth(), cs.GetHeight()); up_to_date = false; } wxBufferedPaintDC dc(this, buffer); // scrolling // int dx = GetScrollPos(wxHORIZONTAL), dy = GetScrollPos(wxVERTICAL); // dc.SetDeviceOrigin(-dx, -dy); wxRegion clip = GetUpdateRegion(); // clip.Offset(dx, dy); dc.SetDeviceClippingRegion(clip); // draw if (!up_to_date) { up_to_date = true; try { draw(dc); } CATCH_ALL_ERRORS(false); // don't show message boxes in onPaint! }
bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { // under MSW we prefer to use the base class version using ::MessageBox() // even if wxMessageBox() is available because it has less chances to // double fault our app than our wxMessageBox() #if defined(__WXMSW__) || !wxUSE_MSGDLG return wxAppTraitsBase::ShowAssertDialog(msg); #else // wxUSE_MSGDLG // this message is intentionally not translated -- it is for // developpers only wxString msgDlg(msg); msgDlg += wxT("\nDo you want to stop the program?\n") wxT("You can also choose [Cancel] to suppress ") wxT("further warnings."); switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), wxYES_NO | wxCANCEL | wxICON_STOP ) ) { case wxYES: wxTrap(); break; case wxCANCEL: // no more asserts return true; //case wxNO: nothing to do } return false; #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG }
bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { // under MSW we prefer to use the base class version using ::MessageBox() // even if wxMessageBox() is available because it has less chances to // double fault our app than our wxMessageBox() // // under DFB the message dialog is not always functional right now // // and finally we can't use wxMessageBox() if it wasn't compiled in, of // course #if defined(__WXMSW__) || defined(__WXDFB__) || !wxUSE_MSGDLG return wxAppTraitsBase::ShowAssertDialog(msg); #else // wxUSE_MSGDLG #if wxDEBUG_LEVEL wxString msgDlg = msg; #if wxUSE_STACKWALKER // on Unix stack frame generation may take some time, depending on the // size of the executable mainly... warn the user that we are working wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); fflush(stderr); const wxString stackTrace = GetAssertStackTrace(); if ( !stackTrace.empty() ) msgDlg << _T("\n\nCall stack:\n") << stackTrace; #endif // wxUSE_STACKWALKER // this message is intentionally not translated -- it is for // developpers only msgDlg += wxT("\nDo you want to stop the program?\n") wxT("You can also choose [Cancel] to suppress ") wxT("further warnings."); switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), wxYES_NO | wxCANCEL | wxICON_STOP ) ) { case wxYES: wxTrap(); break; case wxCANCEL: // no more asserts return true; //case wxNO: nothing to do } #else // !wxDEBUG_LEVEL // this function always exists (for ABI compatibility) but is never called // if debug level is 0 and so can simply do nothing then wxUnusedVar(msg); #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL return false; #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG }
bool wxGUIAppTraits::ShowAssertDialog(const wxString& msg) { #if wxDEBUG_LEVEL // we can't show the dialog from another thread if ( wxIsMainThread() ) { // under GTK2 we prefer to use a dialog widget written using directly // in GTK+ as use a dialog written using wxWidgets would need the // wxWidgets idle processing to work correctly which might not be the // case when assert happens GtkWidget *dialog = gtk_assert_dialog_new(); gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog), msg.mb_str()); #if wxUSE_STACKWALKER // save the current stack ow... StackDump dump(GTK_ASSERT_DIALOG(dialog)); dump.SaveStack(100); // showing more than 100 frames is not very useful // ...but process it only if the user needs it gtk_assert_dialog_set_backtrace_callback ( GTK_ASSERT_DIALOG(dialog), (GtkAssertDialogStackFrameCallback)get_stackframe_callback, &dump ); #endif // wxUSE_STACKWALKER gint result = gtk_dialog_run(GTK_DIALOG (dialog)); bool returnCode = false; switch (result) { case GTK_ASSERT_DIALOG_STOP: wxTrap(); break; case GTK_ASSERT_DIALOG_CONTINUE: // nothing to do break; case GTK_ASSERT_DIALOG_CONTINUE_SUPPRESSING: // no more asserts returnCode = true; break; default: wxFAIL_MSG( wxT("unexpected return code from GtkAssertDialog") ); } gtk_widget_destroy(dialog); return returnCode; } #endif // wxDEBUG_LEVEL return wxAppTraitsBase::ShowAssertDialog(msg); }
bool wxGUIAppTraits::ShowAssertDialog(const wxString& msg) { #if wxDEBUG_LEVEL // under GTK2 we prefer to use a dialog widget written using directly in // GTK+ as use a dialog written using wxWidgets would need the wxWidgets // idle processing to work correctly which might not be the case when // assert happens GtkWidget *dialog = gtk_assert_dialog_new(); gtk_assert_dialog_set_message(GTK_ASSERT_DIALOG(dialog), msg.mb_str()); #if wxUSE_STACKWALKER // 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; // save current stack frame... StackDump dump(GTK_ASSERT_DIALOG(dialog)); dump.SaveStack(maxLines); // ...but process it only if the user needs it gtk_assert_dialog_set_backtrace_callback(GTK_ASSERT_DIALOG(dialog), (GtkAssertDialogStackFrameCallback)get_stackframe_callback, &dump); #endif // wxUSE_STACKWALKER gint result = gtk_dialog_run(GTK_DIALOG (dialog)); bool returnCode = false; switch (result) { case GTK_ASSERT_DIALOG_STOP: wxTrap(); break; case GTK_ASSERT_DIALOG_CONTINUE: // nothing to do break; case GTK_ASSERT_DIALOG_CONTINUE_SUPPRESSING: // no more asserts returnCode = true; break; default: wxFAIL_MSG( _T("unexpected return code from GtkAssertDialog") ); } gtk_widget_destroy(dialog); return returnCode; #else // !wxDEBUG_LEVEL // this function is never called in this case wxUnusedVar(msg); return false; #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL }
bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { #if wxDEBUG_LEVEL // under MSW we prefer to use the base class version using ::MessageBox() // even if wxMessageBox() is available because it has less chances to // double fault our app than our wxMessageBox() // // under DFB the message dialog is not always functional right now // // and finally we can't use wxMessageBox() if it wasn't compiled in, of // course #if !defined(__WXMSW__) && !defined(__WXDFB__) && wxUSE_MSGDLG // we can't (safely) show the GUI dialog from another thread, only do it // for the asserts in the main thread if ( wxIsMainThread() ) { wxString msgDlg = msg; #if wxUSE_STACKWALKER const wxString stackTrace = GetAssertStackTrace(); if ( !stackTrace.empty() ) msgDlg << wxT("\n\nCall stack:\n") << stackTrace; #endif // wxUSE_STACKWALKER // this message is intentionally not translated -- it is for // developpers only msgDlg += wxT("\nDo you want to stop the program?\n") wxT("You can also choose [Cancel] to suppress ") wxT("further warnings."); switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), wxYES_NO | wxCANCEL | wxICON_STOP ) ) { case wxYES: wxTrap(); break; case wxCANCEL: // no more asserts return true; //case wxNO: nothing to do } return false; } #endif // wxUSE_MSGDLG #endif // wxDEBUG_LEVEL return wxAppTraitsBase::ShowAssertDialog(msg); }
bool DoShowAssertDialog(const wxString& msg) { // under MSW we can show the dialog even in the console mode #if defined(__WXMSW__) && !defined(__WXMICROWIN__) wxString msgDlg(msg); // this message is intentionally not translated -- it is for // developpers only msgDlg += wxT("\nDo you want to stop the program?\n") wxT("You can also choose [Cancel] to suppress ") wxT("further warnings."); switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), MB_YESNOCANCEL | MB_ICONSTOP ) ) { case IDYES: wxTrap(); break; case IDCANCEL: // stop the asserts return true; //case IDNO: nothing to do } #else // !__WXMSW__ wxFprintf(stderr, wxT("%s\n"), msg.c_str()); fflush(stderr); // TODO: ask the user to enter "Y" or "N" on the console? wxTrap(); #endif // __WXMSW__/!__WXMSW__ // continue with the asserts return false; }
void BOINCAssertHandler(const wxString &file, int line, const wxString &func, const wxString &cond, const wxString &msg) { wxLogTrace( wxT("Assert"), wxT("ASSERT: %s:%d - %s - %s - %s"), file.IsEmpty() ? wxT("<NULL>") : file.c_str(), line, func.IsEmpty() ? wxT("<NULL>") : func.c_str(), cond.IsEmpty() ? wxT("<NULL>") : cond.c_str(), msg.IsEmpty() ? wxT("<NULL>") : msg.c_str() ); if (wxIsDebuggerRunning()) { wxTrap(); } }
void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& handled) { sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize; if ((offset < 0) || ((uptr)offset >= m_pages_reserved)) return; if (!m_allow_writes) { pxFailRel( pxsFmt( L"Memory Protection Fault @ %s (%s)\n" L"Modification of this reserve has been disabled (m_allow_writes == false).", pxsPtr(info.addr), m_name.c_str()) ); return; } // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't // we let the C++ exception try to unwind the stack, we may not be able to log it either. // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel // implementations seem to support it). // Note also that logging the exception and/or issuing an assertion dialog are always // possible if the thread handling the signal is not the main thread. // In windows we can let exceptions bubble out of the page fault handler. SEH will more // or less handle them in a semi-expected way, and might even avoid a GPF long enough // for the system to log the error or something. #ifndef __WXMSW__ try { #endif DoCommitAndProtect( offset ); handled = true; #ifndef __WXMSW__ } catch (Exception::BaseException& ex) { handled = false; if (!wxThread::IsMain()) { pxFailRel( ex.FormatDiagnosticMessage() ); } else { wxTrap(); } } #endif }
// Linux implementation of SIGSEGV handler. Bind it using sigaction(). static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) { // [TODO] : Add a thread ID filter to the Linux Signal handler here. // Rationale: On windows, the __try/__except model allows per-thread specific behavior // for page fault handling. On linux, there is a single signal handler for the whole // process, but the handler is executed by the thread that caused the exception. // Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done // from the context of the current thread and stackframe. So long as the thread is not // the main/ui thread, use of the px assertion system should be safe. Use of stdio should // be safe even on the main thread. // (in other words, stdio limitations only really apply to process-level asynchronous // signals) // Note: Use of stdio functions isn't safe here. Avoid console logs, // assertions, file logs, or just about anything else useful. // Note: This signal can be accessed by the EE or MTVU thread // Source_PageFault is a global variable with its own state information // so for now we lock this exception code unless someone can fix this better... Threading::ScopedLock lock(PageFault_Mutex); Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) ); // resumes execution right where we left off (re-executes instruction that // caused the SIGSEGV). if (Source_PageFault->WasHandled()) return; if (!wxThread::IsMain()) { pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr)); } // Bad mojo! Completely invalid address. // Instigate a trap if we're in a debugger, and if not then do a SIGKILL. wxTrap(); if (!IsDebugBuild) raise( SIGKILL ); }
// show the assert modal dialog static void ShowAssertDialog(const wxChar *szFile, int nLine, const wxChar *szCond, const wxChar *szMsg, wxAppTraits *traits) { // this variable can be set to true to suppress "assert failure" messages static bool s_bNoAsserts = false; wxString msg; msg.reserve(2048); // make life easier for people using VC++ IDE by using this format: like // this, clicking on the message will take us immediately to the place of // the failed assert msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); if ( szMsg ) { msg << _T(": ") << szMsg; } else // no message given { msg << _T('.'); } #if wxUSE_STACKWALKER const wxString stackTrace = GetAssertStackTrace(); if ( !stackTrace.empty() ) { msg << _T("\n\nCall stack:\n") << stackTrace; } #endif // wxUSE_STACKWALKER #if wxUSE_THREADS // if we are not in the main thread, output the assert directly and trap // since dialogs cannot be displayed if ( !wxThread::IsMain() ) { msg += wxT(" [in child thread]"); #if defined(__WXMSW__) && !defined(__WXMICROWIN__) msg << wxT("\r\n"); OutputDebugString(msg ); #else // send to stderr wxFprintf(stderr, wxT("%s\n"), msg.c_str()); fflush(stderr); #endif // He-e-e-e-elp!! we're asserting in a child thread wxTrap(); } else #endif // wxUSE_THREADS if ( !s_bNoAsserts ) { // send it to the normal log destination wxLogDebug(_T("%s"), msg.c_str()); if ( traits ) { // delegate showing assert dialog (if possible) to that class s_bNoAsserts = traits->ShowAssertDialog(msg); } else // no traits object { // fall back to the function of last resort s_bNoAsserts = DoShowAssertDialog(msg); } } }
bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) { #if defined(__WXMSW__) || !wxUSE_MSGDLG // under MSW we prefer to use the base class version using ::MessageBox() // even if wxMessageBox() is available because it has less chances to // double fault our app than our wxMessageBox() return wxAppTraitsBase::ShowAssertDialog(msg); #else // wxUSE_MSGDLG wxString msgDlg = msg; #if wxUSE_STACKWALKER // on Unix stack frame generation may take some time, depending on the // size of the executable mainly... warn the user that we are working wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); fflush(stderr); const wxString stackTrace = GetAssertStackTrace(); if ( !stackTrace.empty() ) msgDlg << _T("\n\nCall stack:\n") << stackTrace; #endif // wxUSE_STACKWALKER // this message is intentionally not translated -- it is for // developpers only msgDlg += wxT("\nDo you want to stop the program?\n") wxT("You can also choose [Cancel] to suppress ") wxT("further warnings."); #ifdef __WXMAC__ // in order to avoid reentrancy problems, use the lowest alert API available CFOptionFlags exitButton; wxMacCFStringHolder cfText(msgDlg); OSStatus err = CFUserNotificationDisplayAlert( 0, kAlertStopAlert, NULL, NULL, NULL, CFSTR("wxWidgets Debug Alert"), cfText, CFSTR("Yes"), CFSTR("No"), CFSTR("Cancel"), &exitButton ); if ( err == noErr ) { switch( exitButton ) { case 0 : // yes wxTrap(); break; case 2 : // cancel // no more asserts return true; case 1 : // no -> nothing to do break ; } } #else switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), wxYES_NO | wxCANCEL | wxICON_STOP ) ) { case wxYES: wxTrap(); break; case wxCANCEL: // no more asserts return true; //case wxNO: nothing to do } #endif return false; #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG }