[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    [patch] make test_regression SIGSEGV safe
From:       Leo Savernik <l.savernik () aon ! at>
Date:       2004-02-09 20:20:40
Message-ID: 200402092120.42092.l.savernik () aon ! at
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello,

I had crashes when running test_regression (which look like a configuration 
problem on my side, not in khtml code), and I couldn't figure out the source 
of them.

Therefore, I made test_regression catch SIGSEGV, SIGABRT, SIGILL, and SIGFPE, 
skip the testcase that caused it (printing an appropriate error msg), and 
continue with the next one.

The rationale behind this is that test_regression should *always* attempt to 
finish all tests, whatever may happen within a dedicated testcase.

The implementation relies on set/longjmp hackery (but one cannot throw 
exceptions within a signal handler and catch them outside of it), and will 
leak memory, but it's still better than keeping test_regression from handling 
all testcases in case of crashes (The leaks should pose minor problems, as 
crashes should only occur very infrequently).

What do you think of it?

mfg
	Leo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFAJ+uYj5jssenUYTsRAmK/AJ9DABgKNIOgoiguyr0n7nGQCXgJ8gCeMAHk
q1QvkjDoK2mlLYjJTfU9QfI=
=rc7T
-----END PGP SIGNATURE-----

["khtml_testregression_1.diff" (text/x-diff)]

Index: test_regression.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/test_regression.cpp,v
retrieving revision 1.60
diff -u -p -r1.60 test_regression.cpp
--- test_regression.cpp	31 Jan 2004 17:15:26 -0000	1.60
+++ test_regression.cpp	9 Feb 2004 19:36:35 -0000
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <kapplication.h>
 #include <qfile.h>
+#include <setjmp.h>
+#include <signal.h>
 // to be able to delete a static protected member pointer in kbrowser...
 // just for memory debugging
 #define protected public
@@ -86,6 +88,8 @@ using namespace KJS;
 
 bool visual = false;
 
+static sigjmp_buf *cur_label = 0;
+
 // -------------------------------------------------------------------------
 
 PartMonitor::PartMonitor(KHTMLPart *_part)
@@ -329,6 +333,24 @@ Value KHTMLPartFunction::call(ExecState 
 
     return result;
 }
+        
+// signal handler
+static void sighandler(int sig) {
+    signal(SIGSEGV, sighandler);
+    signal(SIGILL, sighandler);
+    signal(SIGFPE, sighandler);
+    if (cur_label) {
+	signal(SIGABRT, sighandler);
+        siglongjmp(*cur_label, sig);
+    }
+
+    signal(SIGABRT, SIG_DFL);
+    const char msg[]="Signal %d occurred. Aborting\n";
+    fflush(stdout); fflush(stderr);
+    printf(msg, sig);
+    fprintf(stderr, msg, sig);
+    abort();
+}
 
 // -------------------------------------------------------------------------
 
@@ -416,6 +438,11 @@ int main(int argc, char *argv[])
     if ( visual )
         toplevel->show();
 
+    signal(SIGSEGV, sighandler);
+    signal(SIGABRT, sighandler);
+    signal(SIGILL, sighandler);
+    signal(SIGFPE, sighandler);
+
     // run the tests
     RegressionTest *regressionTest = new RegressionTest(part,
                                                         args->arg(0),
@@ -563,6 +590,18 @@ bool RegressionTest::runTests(QString re
 	}
     }
     else if (info.isFile()) {
+        sigjmp_buf recover_label;
+	int signum = sigsetjmp(recover_label, true);
+	if (signum) {
+	    cur_label = 0;
+	    reportResult(false, QString("Signal %1 caught").arg(signum), true);
+	    fprintf(stderr, "!!! SIGNAL %d caught while processing %s !!!\n",
+	    	signum, info.fileName().latin1());
+	    return false;
+	}
+
+	cur_label = &recover_label;
+
         khtml::Cache::init();
 
 	QString relativeDir = QFileInfo(relPath).dirPath();
@@ -579,8 +618,11 @@ bool RegressionTest::runTests(QString re
 	}
 	else if (mustExist) {
 	    fprintf(stderr,"%s: Not a valid test file (must be .htm(l) or .js)\n",relPath.latin1());
+	    cur_label = 0;
 	    return false;
 	}
+
+	cur_label = 0;
     } else if (mustExist) {
         fprintf(stderr,"%s: Not a regular file\n",relPath.latin1());
         return false;
@@ -923,12 +965,15 @@ bool RegressionTest::checkOutput(const Q
     return result;
 }
 
-bool RegressionTest::reportResult(bool passed, const QString & description)
+bool RegressionTest::reportResult(bool passed, const QString & description, bool error)
 {
     if (m_genOutput)
 	return true;
 
-    if (passed) {
+    if (error) {
+        printf("ERROR: ");
+	m_errors++;
+    } else if (passed) {
         if ( m_known_failures & AllFailure ) {
             printf("PASS (unexpected!): ");
             m_passes_fail++;
@@ -959,7 +1004,8 @@ bool RegressionTest::reportResult(bool p
     }
 
     printf("\n");
-    return passed;
+    fflush(stdout);
+    return passed && !error;
 }
 
 void RegressionTest::createMissingDirs(QString path)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic