Blob Blame History Raw
From 7041b065a5f9da9901dba4cd95c93eda1a7462eb Mon Sep 17 00:00:00 2001
From: zdenekc <zdenekc@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Date: Wed, 1 Jun 2011 09:41:28 +0000
Subject: [PATCH] * fix failed test exit in no-fork mode

git-svn-id: https://check.svn.sourceforge.net/svnroot/check/trunk@603 64e312b2-a51f-0410-8e61-82d0ca0eb02a
---
 NEWS                       |    5 +++++
 src/check.c                |    2 ++
 src/check_error.c          |    6 ++++++
 src/check_error.h          |    4 ++++
 src/check_run.c            |   25 +++++++++++++++++++------
 tests/Makefile.am          |    5 +++++
 tests/check_nofork.c       |   37 +++++++++++++++++++++++++++++++++++++
 tests/test_check_nofork.sh |   14 ++++++++++++++
 8 files changed, 92 insertions(+), 6 deletions(-)
 create mode 100644 tests/check_nofork.c
 create mode 100755 tests/test_check_nofork.sh

diff --git a/NEWS b/NEWS
index ef52353fe2eb8214aeac87bbfd23dd349525761b..7aa15ee931c412c9ff027dbcb52068db57bee1da 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+In development.
+
+* Added longjmp to fail function to ensure that no code will be executed in test
+  function after failed assertion
+
 Tue, Sep 22, 2009: Released Check 0.9.8
   based on r559 (2009-09-23 21:00).
 
diff --git a/src/check.c b/src/check.c
index 41b9e793cd8c0e85261c1537bc10ad7aec7cb375..a8e8a983d20c18d7aec7ecad6cea2de37ecd2760 100644
--- a/src/check.c
+++ b/src/check.c
@@ -232,6 +232,8 @@ void _fail_unless (int result, const char *file,
 #ifdef _POSIX_VERSION
       exit(1);
 #endif /* _POSIX_VERSION */
+    } else {
+      longjmp(error_jmp_buffer, 1);
     }
   }
 }
diff --git a/src/check_error.c b/src/check_error.c
index 5ed0c1d8ae48eb153ae6f929f48680f629de04f5..588f616ac0925fdf067b8572c45b13e4f7edec0f 100644
--- a/src/check_error.c
+++ b/src/check_error.c
@@ -25,9 +25,15 @@
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <setjmp.h>
 
 #include "check_error.h"
 
+/**
+ * Storage for setjmp/longjmp context information used in NOFORK mode
+ */
+jmp_buf error_jmp_buffer;
+
 
 /* FIXME: including a colon at the end is a bad way to indicate an error */
 void eprintf (const char *fmt, const char *file, int line, ...)
diff --git a/src/check_error.h b/src/check_error.h
index 2e1e211bea24f364b085692d569bed7aa529204c..75be45db7b7c883ae886e272502d16177453bd33 100644
--- a/src/check_error.h
+++ b/src/check_error.h
@@ -21,6 +21,10 @@
 #ifndef ERROR_H
 #define ERROR_H
 
+#include <setjmp.h>
+
+extern jmp_buf error_jmp_buffer;
+
 /* Include stdlib.h beforehand */
 
 /* Print error message and die
diff --git a/src/check_run.c b/src/check_run.c
index 374bf4a0c7ad26402c21f480a02926a0373ec172..faa3ee16f81509c833ebf0d4d42182c11e209631 100644
--- a/src/check_run.c
+++ b/src/check_run.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <signal.h>
+#include <setjmp.h>
 
 #include "check.h"
 #include "check_error.h"
@@ -48,6 +49,7 @@ enum tf_type {
   CK_NOFORK_FIXTURE
 };
 
+
 /* all functions are defined in the same order they are declared.
    functions that depend on forking are gathered all together.
    non-static functions are at the end of the file. */
@@ -205,7 +207,10 @@ static int srunner_run_unchecked_setup (SRunner *sr, TCase *tc)
   for (list_front(l); !list_at_end(l); list_advance(l)) {
     send_ctx_info(CK_CTX_SETUP);
     f = list_val(l);
-    f->fun();
+
+    if ( 0 == setjmp(error_jmp_buffer) ) {
+      f->fun();
+    }
 
     tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
 
@@ -229,18 +234,24 @@ static TestResult * tcase_run_checked_setup (SRunner *sr, TCase *tc)
   List *l;
   Fixture *f;
   enum fork_status fstat = srunner_fork_status(sr);
-  
+
   l = tc->ch_sflst;
   if (fstat == CK_FORK) {
     send_ctx_info(CK_CTX_SETUP);
   }
-  
+
   for (list_front(l); !list_at_end(l); list_advance(l)) {
+    f = list_val(l);
+
     if (fstat == CK_NOFORK) {
       send_ctx_info(CK_CTX_SETUP);
+
+      if ( 0 == setjmp(error_jmp_buffer) ) {
+        f->fun();
+      }
+    } else {
+      f->fun();
     }
-    f = list_val(l);
-    f->fun();
 
     /* Stop the setup and return the failure if nofork mode. */
     if (fstat == CK_NOFORK) {
@@ -294,7 +305,9 @@ static TestResult *tcase_run_tfun_nofork (SRunner *sr, TCase *tc, TF *tfun, int
   
   tr = tcase_run_checked_setup(sr, tc);
   if (tr == NULL) {
-    tfun->fn(i);
+    if ( 0 == setjmp(error_jmp_buffer) ) {
+      tfun->fn(i);
+    }
     tcase_run_checked_teardown(tc);
     return receive_result_info_nofork(tc->name, tfun->name, i);
   }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0e8ddc70c0f7bccb24637f6f99ac1e6b2406a9cf..be00f040ed04daa07fca47230243dbb9f0f9c362 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,6 +4,7 @@ TESTS = \
 	check_check_export	\
 	check_check		\
 	test_output.sh		\
+	test_check_nofork.sh \
 	test_xml_output.sh	\
 	test_log_output.sh
 
@@ -20,6 +21,7 @@ noinst_PROGRAMS = \
 	check_check	\
 	check_stress	\
 	check_thread_stress \
+	check_nofork \
 	ex_output	\
 	ex_xml_output	\
 	ex_log_output
@@ -63,6 +65,9 @@ check_thread_stress_SOURCES = check_thread_stress.c
 check_thread_stress_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la @PTHREAD_LIBS@
 check_thread_stress_CFLAGS = @PTHREAD_CFLAGS@
 
+check_nofork_SOURCES = check_nofork.c
+check_nofork_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la
+
 ex_output_SOURCES = ex_output.c
 ex_output_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la
 
diff --git a/tests/check_nofork.c b/tests/check_nofork.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7310d7a3cf8c2c73f513b0b048ddef3aedb2639
--- /dev/null
+++ b/tests/check_nofork.c
@@ -0,0 +1,37 @@
+#include "../lib/libcompat.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <check.h>
+
+
+Suite *s;
+TCase *tc;
+SRunner *sr;
+
+START_TEST(test_nofork_exit)
+{
+  char* s = NULL;
+
+  ck_assert(NULL != s);
+
+  /* this test should not crash in nofork mode */
+  ck_assert_str_eq("test", s);
+}
+END_TEST
+
+int main(void)
+{
+  s = suite_create("NoFork");
+  tc = tcase_create("Exit");
+  sr = srunner_create(s);
+
+  suite_add_tcase(s, tc);
+  tcase_add_test(tc, test_nofork_exit);
+
+  srunner_set_fork_status(sr, CK_NOFORK);
+  srunner_run_all(sr, CK_MINIMAL);
+  srunner_free(sr);
+
+  return 0;
+}
diff --git a/tests/test_check_nofork.sh b/tests/test_check_nofork.sh
new file mode 100755
index 0000000000000000000000000000000000000000..62276e93541ffc1d683d9fbb40f55ef491d66ba8
--- /dev/null
+++ b/tests/test_check_nofork.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+expected="Running suite(s): NoFork
+0%: Checks: 1, Failures: 1, Errors: 0"
+
+actual=`./check_nofork 2>&1`
+if [ x"${expected}" = x"${actual}" ]; then
+  exit 0
+else
+  echo "Problem with check_nofork"
+  echo "Expected: Failure"
+  echo "Got: Segmentation fault"
+  exit 1
+fi
-- 
1.7.10.1