/* * Hook into the qWarning/qFatal mechanism so that we can channel messages * from libpng to the user. * * Some JPL WMS images tend to overload the libpng 1.2.2 implementation * somehow (especially when zoomed in) * and it would be useful for the user to know why their picture turned up blank * * Based on qInstallMsgHandler example code in the Qt documentation. * */ void myMessageOutput( QtMsgType type, const char *msg ) { switch ( type ) { case QtDebugMsg: myPrint( "%s\n", msg ); if ( strncmp( msg, "Backtrace", 9 ) == 0 ) dumpBacktrace( atoi( msg + 9 ) ); break; case QtCriticalMsg: myPrint( "Critical: %s\n", msg ); break; case QtWarningMsg: myPrint( "Warning: %s\n", msg ); #ifdef QGISDEBUG // Print all warnings except setNamedColor. // Only seems to happen on windows if ( 0 != strncmp( msg, "QColor::setNamedColor: Unknown color name 'param", 48 ) ) { // TODO: Verify this code in action. dumpBacktrace( 20 ); QgsMessageLog::logMessage( msg, "Qt" ); } #endif // TODO: Verify this code in action. if ( 0 == strncmp( msg, "libpng error:", 13 ) ) { // Let the user know QgsMessageLog::logMessage( msg, "libpng" ); } break; case QtFatalMsg: { myPrint( "Fatal: %s\n", msg ); #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__) qgisCrash( -1 ); #else dumpBacktrace( 256 ); abort(); // deliberately dump core #endif } #if QT_VERSION >= 0x050500 case QtInfoMsg: myPrint( "Info: %s\n", msg ); break; #endif } }
//----------------------------------------------------------------------------// Exception::Exception(const String& message, const String& name, const String& filename, int line, const String& function) : d_message(message), d_name(name), d_filename(filename), d_line(line), d_function(function), d_what(name + " in function '" + function + "' (" + filename + ":" + PropertyHelper<int>::toString(line) + ") : " + message) { // Log exception if possible if (Logger* const logger = Logger::getSingletonPtr()) { logger->logEvent(d_what, Errors); dumpBacktrace(64); } if (d_stdErrEnabled) { // output to stderr unless it's explicitly disabled // nobody seems to look in their log file! std::cerr << what() << std::endl; } }
void handleCrash(int signalNumber, siginfo_t *sigInfo, void *context) { static volatile sig_atomic_t fatal_error_in_progress = 0; if (fatal_error_in_progress) //Stop a signal loop. _exit(1); fatal_error_in_progress = 1; char *j; char *signumber = strdup(sys_signame[signalNumber]); upcase(signumber); asprintf(&j, "Crash Signal: %s, crashed on: %li, UID: %ld\n", signumber, (long) sigInfo->si_addr, (long) sigInfo->si_uid); //%x prints out the faulty memory address in hex LOGE("%s", j); const size_t max = 30; void *buffer[max]; std::ostringstream oss; bool encodingCrash = dumpBacktrace(oss, buffer, captureBacktrace(buffer, max)); LOGE("%s", oss.str().c_str()); if (encodingCrash) { pthread_t *id = (pthread_t *) malloc(sizeof(pthread_t)); pthread_create(id, NULL, notifyThread, NULL); pthread_join(*id, NULL); } call_old_signal_handler(signalNumber, sigInfo, context); }
// The signal handler. If this function is called, it means shit has probably collided with some sort of device one might use to keep oneself cool. // This is the generic part of the code that will be called after platform specific handling is finished. void handleCrash(CrashData crash) { #ifdef Q_OS_UNIX fprintf(stderr, "Fatal error! Received signal %d\n", crash.signal); #endif time_t unixTime = 0; // Unix timestamp. Used to give our crash dumps "unique" names. char dumpFileName[DUMPF_NAME_LEN]; // The name of the file we're dumping to. int dumpFile; // File descriptor for our dump file. // Determine what our dump file should be called. // We'll just call it "mmc-crash-<unixtime>.dump" // First, check the time. time(&unixTime); // Now we get to do some !!FUN!! hackery to ensure we don't use the stack when we convert // the timestamp from an int to a string. To do this, we just allocate a fixed size array // of chars on the stack, and sprintf into it. We know the timestamp won't ever be longer // than a certain number of digits, so this should work just fine. // sprintf doesn't support writing signed values as hex, so this breaks on negative timestamps. // It really shouldn't matter, though... sprintf(dumpFileName, DUMPF_NAME_FMT, unixTime); // Now, we need to open the file. // Fail if it already exists. This should never happen. dumpFile = open(dumpFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (dumpFile >= 0) { // If we opened the dump file successfully. // Dump everything we can and GTFO. fprintf(stderr, "Dumping crash report to %s\n", dumpFileName); // Dump misc info dprintf(dumpFile, "Unix Time: %d\n", unixTime); dumpErrorInfo(dumpFile, crash); dumpMiscInfo(dumpFile); dprintf(dumpFile, "\n"); dumpSysInfo(dumpFile); dprintf(dumpFile, "\n"); dumpBacktrace(dumpFile, crash); dprintf(dumpFile, "\n"); // DIE DIE DIE! exit(1); } else { fprintf(stderr, "Failed to open dump file %s to write crash info (ERRNO: %d)\n", dumpFileName, errno); exit(2); } }
void printStackTrace(unsigned int max_frames) { void* buffer[max_frames]; std::ostringstream oss; dumpBacktrace(oss, buffer, captureBacktrace(buffer, max_frames)); __android_log_print(ANDROID_LOG_DEBUG, TAG, "%s", oss.str().c_str()); }
void qgisCrash( int signal ) { fprintf( stderr, "QGIS died on signal %d", signal ); if ( access( "/usr/bin/gdb", X_OK ) == 0 ) { // take full stacktrace using gdb // http://stackoverflow.com/questions/3151779/how-its-better-to-invoke-gdb-from-program-to-print-its-stacktrace // unfortunately, this is not so simple. the proper method is way more OS-specific // than this code would suggest, see http://stackoverflow.com/a/1024937 char exename[512]; #if defined(__FreeBSD__) int len = readlink( "/proc/curproc/file", exename, sizeof( exename ) - 1 ); #else int len = readlink( "/proc/self/exe", exename, sizeof( exename ) - 1 ); #endif if ( len < 0 ) { myPrint( "Could not read link (%d:%s)\n", errno, strerror( errno ) ); } else { exename[ len ] = 0; char pidstr[32]; snprintf( pidstr, sizeof pidstr, "--pid=%d", getpid() ); int gdbpid = fork(); if ( gdbpid == 0 ) { // attach, backtrace and continue execl( "/usr/bin/gdb", "gdb", "-q", "-batch", "-n", pidstr, "-ex", "thread", "-ex", "bt full", exename, NULL ); perror( "cannot exec gdb" ); exit( 1 ); } else if ( gdbpid >= 0 ) { int status; waitpid( gdbpid, &status, 0 ); myPrint( "gdb returned %d\n", status ); } else { myPrint( "Cannot fork (%d:%s)\n", errno, strerror( errno ) ); dumpBacktrace( 256 ); } } } abort(); }
void avgAssert(bool b, const char * pszFile, int line, const char * pszReason) { if (!b) { string sDummy; static bool bBreak = getEnv("AVG_BREAK_ON_ASSERT", sDummy); if (bBreak) { debugBreak(); } else { stringstream ss; ss << "Assertion failed in " << pszFile << ": " << line << endl; if (pszReason) { ss << "Reason: " << pszReason << endl; } dumpBacktrace(); throw(Exception(AVG_ERR_ASSERT_FAILED, ss.str())); } } }
void Ref::release() { CCASSERT(_referenceCount > 0, "reference count should be greater than 0"); if(_referenceCount <= 0){ return; } --_referenceCount; auto poolManager = PoolManager::getInstance(); if (_isInAutoPool&&poolManager->isClearing()) { _isInAutoPool = false; } if (_referenceCount == 0) { //auto poolManager = PoolManager::getInstance(); if (_isInAutoPool&&!poolManager->isClearing() )//&& poolManager->isObjectInPools(this)) { poolManager->removeObject(this); } #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) // auto poolManager = PoolManager::getInstance(); // if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this)) // { // } // Trigger an assert if the reference count is 0 but the Ref is still in autorelease pool. // This happens when 'autorelease/release' were not used in pairs with 'new/retain'. // // Wrong usage (1): // // auto obj = Node::create(); // Ref = 1, but it's an autorelease Ref which means it was in the autorelease pool. // obj->autorelease(); // Wrong: If you wish to invoke autorelease several times, you should retain `obj` first. // // Wrong usage (2): // // auto obj = Node::create(); // obj->release(); // Wrong: obj is an autorelease Ref, it will be released when clearing current pool. // // Correct usage (1): // // auto obj = Node::create(); // |- new Node(); // `new` is the pair of the `autorelease` of next line // |- autorelease(); // The pair of `new Node`. // // obj->retain(); // obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line. // // Correct usage (2): // // auto obj = Node::create(); // obj->retain(); // obj->release(); // This `release` is the pair of `retain` of previous line. // CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool."); // } #endif #if CC_REF_LEAK_DETECTION untrackRef(this); #endif if ( g_performanceCrashSwitch && _isInAutoPool && !poolManager->isClearing() ) { #ifdef CC_ENABLE_BACKTRACE const size_t max = 30; void* buffer[max]; dumpBacktrace( buffer, captureBacktrace(buffer, max)); #endif int *pTest = NULL; *pTest = 123456; } delete this; } }