Bug #1239: build fails for OpenBSD: [BUG] register_sigaltstack. error
http://redmine.ruby-lang.org/issues/show/1239

Author: George Koehler
Status: Open, Priority: Normal
ruby -v: ruby 1.9.1p0 (2009-01-30 revision 21907) [powerpc-openbsd4.5]

I have a computer with OpenBSD and I tried Ruby 1.9.1. So I obtained the source code, configured with "../configure --prefix=$HOME/prefix" and did "make". The build failed with an error. My computer has a PowerPC processor and the operating system is OpenBSD 4.5-beta.

Here I use "make -dl" to show the miniruby command causing the error:

<pre>
$ make -dl
./miniruby -I./lib -I.ext/common -I./- -r./ext/purelib.rb  ./mkconfig.rb -timestamp=./.rbconfig.time  -install_name=ruby  -so_name=ruby rbconfig.rb
[BUG] register_sigaltstack. error

ruby 1.9.1p0 (2009-01-30 revision 21907) [powerpc-openbsd4.5]

-- control frame ----------
c:0001 p:---- s:0002 b:0002 l:000001 d:000001 TOP
---------------------------
Segmentation fault (core dumped)
*** Error code 139

Stop in /home/kernigh/park/ruby-wrong/ruby-1.9.1-p0 (line 691 of Makefile).
</pre>

The same error happens if I do "./miniruby" with no arguments.

I looked in the Ruby source code. I found that "register_sigaltstack. error" happens if the call to sigaltstack() fails. So I searched for why sigaltstack() fails. I found the answer in the source code of the OpenBSD pthreads library.

OpenBSD does not have kernel threads. The OpenBSD pthreads library implements threads in userspace. (OpenBSD is the only operating system, that I know, where pthreads are not kernel threads. They say that Ruby 1.9 uses kernel threads, but this is not true for OpenBSD!) The OpenBSD pthreads library does override multiple libc functions, including sigaltstack().

Here is the comment in OpenBSD src/lib/libpthread/uthread/uthread_sigaltstack.c

<pre>
/*
 * IEEE Std 1003.1-2001 says:
 *
 * "Use of this function by library threads that are not bound to
 * kernel-scheduled entities results in undefined behavior."
 *
 * There exists code (e.g. alpha setjmp) that uses this function
 * to get information about the current stack.
 *
 * The "undefined behaviour" in this implementation is thus:
 * o if ss is *not* null return -1 with errno set to EINVAL
 * o if oss is *not* null fill it in with information about the
 *   current stack and return 0.
 *
 * This lets things like alpha setjmp work in threaded applications.
 */

int
sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
{
	struct pthread *curthread = _get_curthread();

	int ret = 0;
	if (ss != NULL) {
		errno = EINVAL;
		ret = -1;
	} else ...
</pre>

So the OpenBSD pthreads library does not allow a separate signal stack. Whenever you give a signal stack to sigaltstack(), it always returns EINVAL.

So I changed my copy of ruby-1.9.1-p0/signal.c to ignore this error.

<pre>
--- signal.c.orig	Wed Jan 28 04:22:07 2009
+++ signal.c	Mon Mar  2 14:11:01 2009
@@ -444,8 +444,13 @@
     newSS.ss_size = ALT_STACK_SIZE;
     newSS.ss_flags = 0;
 
-    if (sigaltstack(&newSS, &oldSS) < 0) 
-	rb_bug("register_sigaltstack. error\n");
+    if (sigaltstack(&newSS, &oldSS) < 0) {
+	if (errno == EINVAL) {
+	    /* ignore error, always happens with OpenBSD pthreads */
+	}
+	else
+	    rb_bug("register_sigaltstack. error\n");
+    }
 }
 #endif
 
</pre>

I left in the call to sigaltstack(), in case OpenBSD ever fixes their broken sigaltstack() function, but I ignored the EINVAL error. (Other ways might be to put an #ifdef __OpenBSD__ somewhere, or to #undef HAVE_SIGALTSTACK with OpenBSD.)

After I made this change to signal.c, I did "make", "make test" and "make install". Ruby seems to work correctly. All tests pass except one test in test_objectspace.rb, that seems to do an infinite loop, so I had to Control-C that test.

<pre>
#703 test_objectspace.rb:13:in `<top (required)>':   [ruby-dev:31911]
FAIL 1/928 tests failed
</pre>

I agree when ruby-1.9.1-p0/README claims that ruby is "Highly Portable". Except for one call to sigaltstack(), everything in Ruby 1.9.1 seems to work with OpenBSD. Though the Ruby manual pages do have a few tiny formatting mistakes, but I will not worry about that until later. I wonder if someone will fix how Ruby uses sigaltstack().


----------------------------------------
http://redmine.ruby-lang.org