Phusion white papers Phusion overview

Phusion Blog

Fixing Nginx PCRE compilation issues on OS X

By Hongli Lai on October 26th, 2012

A lot of people running OS X (including us!) have recently been suffering from problems with compiling Nginx. Compilation would fail with the error message that the symbol pcre_free_study is not found, within the context of the function pcre_free_studies in ngx_regex.o:

src/core/ngx_regex.o: In function `ngx_pcre_free_studies':
    src/core/ngx_regex.c:307: undefined reference to `pcre_free_study'
collect2: ld returned 1 exit status
make[1]: *** [objs/nginx] Error 1

What is pcre_free_study? A Google search revealed that it is related to recently added support for JIT compilation in the PCRE library, a regular expressions library used by Nginx.

Upon further inspection, it turns out that a recent OS X update installed /usr/lib/libpcre.0.dylib and /usr/include/pcre.h. OS X did not ship PCRE in the past and users had to manually install it with MacPorts or HomeBrew. However, the library that OS X now ships seems to be of a different version than the header file!

$ strings /usr/lib/libpcre.0.dylib | grep -F 8.
8.02 2010-03-19
$ less /usr/include/pcre.h
....
/* The current PCRE version information. */

#define PCRE_MAJOR          8
#define PCRE_MINOR          31
#define PCRE_PRERELEASE     
#define PCRE_DATE           2012-07-06

The compilation problem is caused by the fact that OS X did not ship a proper header file for PCRE. You can solve this problem by downloading the header file for PCRE 8.02 and copying it to /usr/include.

How to fix the Ruby 1.9 HTTPS/Bundler segmentation fault on OS X Lion

By Hongli Lai on May 9th, 2012

If you’ve installed a gem bundle on OS X Lion the past few weeks then you may have seen the dreaded “[BUG] Segmentation fault” error, where Ruby sees to crash in the connect C function in http.rb. Upgrading to the latest Ruby 1.9.3 version (p194) doesn’t seem to help. Luckily someone has found a solution for this problem.

It turns out the segmentation fault is caused by an incompatibility between MacPort’s OpenSSL and RVM. MacPorts installs everything to /opt/local but RVM does not look for OpenSSL in /opt/local. We solved the problem by reinstalling Ruby 1.9.3 with the MacPorts OpenSSL, as follows.

First edit $HOME/.rvmrc and add:

export CFLAGS="-O2 -arch x86_64"
export LDFLAGS="-L/opt/local/lib"
export CPPFLAGS="-I/opt/local/include"

Then run:

sudo port install libyaml
rvm reinstall ruby-1.9.3 --with-openssl-dir=/opt/local --with-opt-dir=/opt/local

XCode 4 ships a buggy compiler

By Hongli Lai on December 30th, 2011

You may have heard of LLVM, a compiler infrastructure library. You may have heard of GCC, the GNU C and C++ compiler. Those two are completely separate software products, but there exists llvm-gcc which is a GCC frontend that utilizes LLVM. All OS X versions <= Snow Leopard originally shipped with regular gcc, but as of Xcode 4 (which is also the default on OS X Lion) Apple has switched to llvm-gcc as their default compiler. “Hurray”, some people may think, as they heard that LLVM generates better code and/or is faster than default GCC. Unfortunately, the reality is not that great.

llvm-gcc is unmaintained and is considered deprecated by its developers. It has many bugs that will never be fixed. Unfortunately these are not obscure bugs that few people will notice: today, while working on Ruby Enterprise Edition, we encountered several! Calling alloca(0) should return a pointer to the top of the stack. On llvm-gcc however, that code returns NULL but only when compiled with -O2! llvm-gcc also generates subtly different code that causes the MBARI patch set to fail completely.

To make matters worse, consider this program:

#include <alloca.h>

int
main() {
    if (alloca(0) != NULL) {
        return 0;
    } else {
        return 1;
    }
}

Question: when compiled with “llvm-gcc -O2”, does this program exit with 0 or with 1?

That was a trick question. It always returns with 0, even when alloca(0) is broken and actually returns NULL. Turns out the optimizer in -O2 thinks that alloca(0) doesn’t return NULL (even though it does) and replaces if (alloca(0) != NULL) with if (true).

It is unfortunate that we have to declare OS X’s default compiler as being broken. We do not recommend its use. Instead, we recommend people to use /usr/bin/gcc-4.2 (which is the non-LLVM GCC compiler) instead of /usr/bin/gcc (which is a symlink to /usr/bin/llvm-gcc). You can enable this on most build systems by setting these two environment variables:

export CC=gcc-4.2
export CXX=g++-4.2

On a side note, Ruby Enterprise Edition 2011.12 is being released. The official announcement hasn’t been written yet, but we’ve made haste because of the recent Ruby security vulnerability. You can already get the files on the Ruby Enterprise Edition website. An announcement will follow soon.

Update

some people have pointed out that they consider alloca(0) undefined. I guess it depends on the way you interpret the documentation. It would seem pretty clear to me what alloca(0) means, just like what memcpy(x, y, 0) means, but it’s understandable when some people would interpret it as undefined.
Still, alloca(0) failing is only one of the problems that prevented Ruby from compiling properly.

Why alloca(0)?

alloca(0) is used in Ruby Enterprise Edition’s conservative garbage collector, as a way to detect the end of the stack. There’s a bunch of fallback #ifdefs in the code: on platforms that don’t have alloca, it detects the end of the stack by calling a forced-non-inline function which returns the address of its sole local variable, but that assumes that the compiler supports the ‘noinline’ keyword. In any case, all of versions depend on highly platform-specific behavior.