You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/12/15 05:21:23 UTC

svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Author: hwright
Date: Wed Dec 15 04:21:23 2010
New Revision: 1049414

URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
Log:
Allow tests which cause segfaults to not disrupt the other tests in the C
testsuite.  This becomes useful when committing an XFailing test of a
segfault (which I will shortly do), or when a test starts segfaulting of
it's own accord.

This behavior is enabled by default, but can be disabled by passing
--allow-segfaults to the test, which should make for better debugging
of the cause of the segfault.

This patch uses setjmp() / longjmp() to accomplish the recovery from a SIGSEGV.
While I'd highly frown upon those function in general purpose use, I believe
this is an understandable exception.  Because it is so rare to use them,
my personal experience is limited, so review and corrections are of course
welcomed.

This patch has been tested on Mac OS only, but I believe it to be portable to
other systems.  I'm relying on the bots to verify that belief.

* subversion/tests/svn_test_main.c
  (allow_segfaults): New variable for storing the option value.
  (allow_segfault_opt): New option flag.
  (cl_options): Add the allow-segfaults flag.
  (jump_buffer, crash_handler): New.
  (do_test_num): Set up the SIGSEGV handler, and introduce a setjmp() call
    to recover from a segfault in the test.  Restore the old behavior when
    done.
  (main): Parse the allow-segfaults option.

Modified:
    subversion/trunk/subversion/tests/svn_test_main.c

Modified: subversion/trunk/subversion/tests/svn_test_main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/svn_test_main.c?rev=1049414&r1=1049413&r2=1049414&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/svn_test_main.c (original)
+++ subversion/trunk/subversion/tests/svn_test_main.c Wed Dec 15 04:21:23 2010
@@ -26,9 +26,11 @@
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <setjmp.h>
 
 #include <apr_pools.h>
 #include <apr_general.h>
+#include <apr_signal.h>
 
 #include "svn_cmdline.h"
 #include "svn_opt.h"
@@ -63,6 +65,9 @@ static svn_boolean_t quiet_mode = FALSE;
 /* Test option: Remove test directories after success */
 static svn_boolean_t cleanup_mode = FALSE;
 
+/* Test option: Allow segfaults */
+static svn_boolean_t allow_segfaults = FALSE;
+
 /* Option parsing enums and structures */
 enum {
   cleanup_opt = SVN_OPT_FIRST_LONGOPT_ID,
@@ -72,7 +77,8 @@ enum {
   trap_assert_opt,
   quiet_opt,
   config_opt,
-  server_minor_version_opt
+  server_minor_version_opt,
+  allow_segfault_opt
 };
 
 static const apr_getopt_option_t cl_options[] =
@@ -94,6 +100,8 @@ static const apr_getopt_option_t cl_opti
                     N_("catch and report SVN_ERR_ASSERT failures")},
   {"quiet",         quiet_opt, 0,
                     N_("print only unexpected results")},
+  {"allow-segfaults", allow_segfault_opt, 0,
+                    N_("don't trap seg faults (useful for debugging)")},
   {0,               0, 0, 0}
 };
 
@@ -175,6 +183,16 @@ get_array_size(void)
   return (i - 1);
 }
 
+/* Buffer used for setjmp/longjmp. */
+static jmp_buf jump_buffer;
+
+/* Our SIGSEGV handler, which jumps back into do_test_num(), which see for
+   more information. */
+static void
+crash_handler(int signum)
+{
+  longjmp(jump_buffer, 1);
+}
 
 
 /* Execute a test number TEST_NUM.  Pretty-print test name and dots
@@ -208,20 +226,44 @@ do_test_num(const char *progname,
   xfail = desc->mode == svn_test_xfail;
   wimp = xfail && desc->wip;
 
-  /* Do test */
-  msg = desc->msg;
-  if (msg_only || skip)
-    ; /* pass */
-  else if (desc->func2)
-    err = (*desc->func2)(pool);
+  if (!allow_segfaults)
+    {
+      /* Catch a crashing test, so we don't interrupt the rest of 'em. */
+      apr_signal(SIGSEGV, crash_handler);
+    }
+
+  /* We use setjmp/longjmp to recover from the crash.  setjmp() essentially
+     establishes a rollback point, and longjmp() goes back to that point.
+     When we invoke longjmp(), it instructs setjmp() to return non-zero,
+     so we don't end up in an infinite loop.
+
+     If we've got non-zero from setjmp(), we know we've crashed. */
+  if (setjmp(jump_buffer) == 0)
+    {
+      /* Do test */
+      msg = desc->msg;
+      if (msg_only || skip)
+        ; /* pass */
+      else if (desc->func2)
+        err = (*desc->func2)(pool);
+      else
+        err = (*desc->func_opts)(opts, pool);
+
+      if (err && err->apr_err == SVN_ERR_TEST_SKIPPED)
+        {
+          svn_error_clear(err);
+          err = SVN_NO_ERROR;
+          skip = TRUE;
+        }
+    }
   else
-    err = (*desc->func_opts)(opts, pool);
+    err = svn_error_create(SVN_ERR_TEST_FAILED, NULL,
+                           "Test crashed (unknown reason)");
 
-  if (err && err->apr_err == SVN_ERR_TEST_SKIPPED)
+  if (!allow_segfaults)
     {
-      svn_error_clear(err);
-      err = SVN_NO_ERROR;
-      skip = TRUE;
+      /* Now back to your regularly scheduled program... */
+      apr_signal(SIGSEGV, SIG_DFL);
     }
 
   /* Failure means unexpected results -- FAIL or XPASS. */
@@ -370,6 +412,9 @@ main(int argc, const char *argv[])
         case quiet_opt:
           quiet_mode = TRUE;
           break;
+        case allow_segfault_opt:
+          allow_segfaults = TRUE;
+          break;
         case server_minor_version_opt:
           {
             char *end;



Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by "Hyrum K. Wright" <hy...@mail.utexas.edu>.
On Sat, Dec 18, 2010 at 2:36 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> hwright@apache.org wrote on Wed, Dec 15, 2010 at 04:21:23 -0000:
>> Author: hwright
>> Date: Wed Dec 15 04:21:23 2010
>> New Revision: 1049414
>>
>> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
>> Log:
>> Allow tests which cause segfaults to not disrupt the other tests in the C
>> testsuite.  This becomes useful when committing an XFailing test of a
>> segfault (which I will shortly do), or when a test starts segfaulting of
>> it's own accord.
>>
>> This behavior is enabled by default, but can be disabled by passing
>> --allow-segfaults to the test, which should make for better debugging
>> of the cause of the segfault.
> ...
>> -    err = (*desc->func_opts)(opts, pool);
>> +    err = svn_error_create(SVN_ERR_TEST_FAILED, NULL,
>> +                           "Test crashed (unknown reason)");
>
> Perhaps the error message could suggest to pass --allow-segfaults?

r1050719.  Thanks.

-Hyrum

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by "Hyrum K. Wright" <hy...@mail.utexas.edu>.
On Sat, Dec 18, 2010 at 2:36 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> hwright@apache.org wrote on Wed, Dec 15, 2010 at 04:21:23 -0000:
>> Author: hwright
>> Date: Wed Dec 15 04:21:23 2010
>> New Revision: 1049414
>>
>> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
>> Log:
>> Allow tests which cause segfaults to not disrupt the other tests in the C
>> testsuite.  This becomes useful when committing an XFailing test of a
>> segfault (which I will shortly do), or when a test starts segfaulting of
>> it's own accord.
>>
>> This behavior is enabled by default, but can be disabled by passing
>> --allow-segfaults to the test, which should make for better debugging
>> of the cause of the segfault.
> ...
>> -    err = (*desc->func_opts)(opts, pool);
>> +    err = svn_error_create(SVN_ERR_TEST_FAILED, NULL,
>> +                           "Test crashed (unknown reason)");
>
> Perhaps the error message could suggest to pass --allow-segfaults?

r1050719.  Thanks.

-Hyrum

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
hwright@apache.org wrote on Wed, Dec 15, 2010 at 04:21:23 -0000:
> Author: hwright
> Date: Wed Dec 15 04:21:23 2010
> New Revision: 1049414
> 
> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
> Log:
> Allow tests which cause segfaults to not disrupt the other tests in the C
> testsuite.  This becomes useful when committing an XFailing test of a
> segfault (which I will shortly do), or when a test starts segfaulting of
> it's own accord.
> 
> This behavior is enabled by default, but can be disabled by passing
> --allow-segfaults to the test, which should make for better debugging
> of the cause of the segfault.
...
> -    err = (*desc->func_opts)(opts, pool);
> +    err = svn_error_create(SVN_ERR_TEST_FAILED, NULL,
> +                           "Test crashed (unknown reason)");

Perhaps the error message could suggest to pass --allow-segfaults?

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by "Hyrum K. Wright" <hy...@mail.utexas.edu>.
On Wed, Dec 15, 2010 at 3:32 AM, Branko Čibej <br...@apache.org> wrote:
> On 15.12.2010 06:17, Blair Zajac wrote:
>> On 12/14/10 8:21 PM, hwright@apache.org wrote:
>>> Author: hwright
>>> Date: Wed Dec 15 04:21:23 2010
>>> New Revision: 1049414
>>>
>>> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
>>> Log:
>>> Allow tests which cause segfaults to not disrupt the other tests in
>>> the C
>>> testsuite.  This becomes useful when committing an XFailing test of a
>>> segfault (which I will shortly do), or when a test starts segfaulting of
>>> it's own accord.
>>>
>>> This behavior is enabled by default, but can be disabled by passing
>>> --allow-segfaults to the test, which should make for better debugging
>>> of the cause of the segfault.
>>>
>>> This patch uses setjmp() / longjmp() to accomplish the recovery from
>>> a SIGSEGV.
>>> While I'd highly frown upon those function in general purpose use, I
>>> believe
>>> this is an understandable exception.  Because it is so rare to use them,
>>> my personal experience is limited, so review and corrections are of
>>> course
>>> welcomed.
>>
>> I've never seen setjmp/longjump used for this, but it's interesting.
>>
>> One question, could you use sigsetjmp/siglongjmp instead of manually
>> putting back disposition the to default with apr_signal?  I guess you
>> would use apr_signal after the sigsetjump in that case.
>
> Are the sig* variants available on all platforms? I don't recall seeing
> them in the C90 stdlib.

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by "Hyrum K. Wright" <hy...@mail.utexas.edu>.
On Wed, Dec 15, 2010 at 3:32 AM, Branko Čibej <br...@apache.org> wrote:
> On 15.12.2010 06:17, Blair Zajac wrote:
>> On 12/14/10 8:21 PM, hwright@apache.org wrote:
>>> Author: hwright
>>> Date: Wed Dec 15 04:21:23 2010
>>> New Revision: 1049414
>>>
>>> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
>>> Log:
>>> Allow tests which cause segfaults to not disrupt the other tests in
>>> the C
>>> testsuite.  This becomes useful when committing an XFailing test of a
>>> segfault (which I will shortly do), or when a test starts segfaulting of
>>> it's own accord.
>>>
>>> This behavior is enabled by default, but can be disabled by passing
>>> --allow-segfaults to the test, which should make for better debugging
>>> of the cause of the segfault.
>>>
>>> This patch uses setjmp() / longjmp() to accomplish the recovery from
>>> a SIGSEGV.
>>> While I'd highly frown upon those function in general purpose use, I
>>> believe
>>> this is an understandable exception.  Because it is so rare to use them,
>>> my personal experience is limited, so review and corrections are of
>>> course
>>> welcomed.
>>
>> I've never seen setjmp/longjump used for this, but it's interesting.
>>
>> One question, could you use sigsetjmp/siglongjmp instead of manually
>> putting back disposition the to default with apr_signal?  I guess you
>> would use apr_signal after the sigsetjump in that case.
>
> Are the sig* variants available on all platforms? I don't recall seeing
> them in the C90 stdlib.

>From my manpage:

The setjmp() and longjmp() functions conform to ISO/IEC 9899:1990
     (``ISO C90'').  The sigsetjmp() and siglongjmp() functions conform to
     IEEE Std 1003.1-1988 (``POSIX.1'').

So it would appear that the sig* variants are not part of the C90 standard.

-Hyrum

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by "C. Michael Pilato" <cm...@collab.net>.
On 12/15/2010 04:32 AM, Branko Čibej wrote:
> Are the sig* variants available on all platforms? I don't recall seeing
> them in the C90 stdlib.

`man setjmp` tells me:

C89, C99, and POSIX.1-2001 specify setjmp().  POSIX.1-2001 specifies
sigsetjmp().

-- 
C. Michael Pilato <cm...@collab.net>
CollabNet   <>   www.collab.net   <>   Distributed Development On Demand


Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by Branko Čibej <br...@apache.org>.
On 15.12.2010 06:17, Blair Zajac wrote:
> On 12/14/10 8:21 PM, hwright@apache.org wrote:
>> Author: hwright
>> Date: Wed Dec 15 04:21:23 2010
>> New Revision: 1049414
>>
>> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
>> Log:
>> Allow tests which cause segfaults to not disrupt the other tests in
>> the C
>> testsuite.  This becomes useful when committing an XFailing test of a
>> segfault (which I will shortly do), or when a test starts segfaulting of
>> it's own accord.
>>
>> This behavior is enabled by default, but can be disabled by passing
>> --allow-segfaults to the test, which should make for better debugging
>> of the cause of the segfault.
>>
>> This patch uses setjmp() / longjmp() to accomplish the recovery from
>> a SIGSEGV.
>> While I'd highly frown upon those function in general purpose use, I
>> believe
>> this is an understandable exception.  Because it is so rare to use them,
>> my personal experience is limited, so review and corrections are of
>> course
>> welcomed.
>
> I've never seen setjmp/longjump used for this, but it's interesting.
>
> One question, could you use sigsetjmp/siglongjmp instead of manually
> putting back disposition the to default with apr_signal?  I guess you
> would use apr_signal after the sigsetjump in that case.

Are the sig* variants available on all platforms? I don't recall seeing
them in the C90 stdlib.

-- Brane

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by Blair Zajac <bl...@orcaware.com>.
On 12/14/10 8:21 PM, hwright@apache.org wrote:
> Author: hwright
> Date: Wed Dec 15 04:21:23 2010
> New Revision: 1049414
>
> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
> Log:
> Allow tests which cause segfaults to not disrupt the other tests in the C
> testsuite.  This becomes useful when committing an XFailing test of a
> segfault (which I will shortly do), or when a test starts segfaulting of
> it's own accord.
>
> This behavior is enabled by default, but can be disabled by passing
> --allow-segfaults to the test, which should make for better debugging
> of the cause of the segfault.
>
> This patch uses setjmp() / longjmp() to accomplish the recovery from a SIGSEGV.
> While I'd highly frown upon those function in general purpose use, I believe
> this is an understandable exception.  Because it is so rare to use them,
> my personal experience is limited, so review and corrections are of course
> welcomed.

I've never seen setjmp/longjump used for this, but it's interesting.

One question, could you use sigsetjmp/siglongjmp instead of manually putting 
back disposition the to default with apr_signal?  I guess you would use 
apr_signal after the sigsetjump in that case.

Blair

Re: svn commit: r1049414 - /subversion/trunk/subversion/tests/svn_test_main.c

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
hwright@apache.org wrote on Wed, Dec 15, 2010 at 04:21:23 -0000:
> Author: hwright
> Date: Wed Dec 15 04:21:23 2010
> New Revision: 1049414
> 
> URL: http://svn.apache.org/viewvc?rev=1049414&view=rev
> Log:
> Allow tests which cause segfaults to not disrupt the other tests in the C
> testsuite.  This becomes useful when committing an XFailing test of a
> segfault (which I will shortly do), or when a test starts segfaulting of
> it's own accord.
> 
> This behavior is enabled by default, but can be disabled by passing
> --allow-segfaults to the test, which should make for better debugging
> of the cause of the segfault.
...
> -    err = (*desc->func_opts)(opts, pool);
> +    err = svn_error_create(SVN_ERR_TEST_FAILED, NULL,
> +                           "Test crashed (unknown reason)");

Perhaps the error message could suggest to pass --allow-segfaults?