At work I manage FreeBSD servers mostly running web applications. One of the databases we need to be able to talk to is an Oracle database, so all I need to be able to do is connect, perform queries, and retrieve results. We need to be able to do this from PHP.

On FreeBSD, one obvious option is to use oracle8-client, which is a binary port of Oracle’s client libraries for Linux. The PHP OCI8 extension port has this as a dependency, so with no configuration aside from building PHP with OCI8 support, you now have oracle8-client on your system.

Everything was incredibly simple to install, except for one problem. Now, with the OCI8 extension enabled in php.ini, the following occurs:


user@host:~> php hello.php
Hello world!
Segmentation fault
user@host:~>

The contents of hello.php don’t matter, but now all PHP scripts run from the command line always segfault on exit. This includes pear and other CLI utilities written in PHP. Using gdb I was able to trace unloading of the OCI8 library to a call in Zend/zend_API.c (DL_UNLOAD) which calls dlclose(3) on a FreeBSD system. After doing some reading, I can only assume that the Oracle library is doing something incorrectly such as registering a function to be called at exit via atexit(3). In that case, we would call dlclose(3) after the function(s) are registered, but then when we exit and those registered functions get called, we get a segmentation fault as we’ve unmapped the memory they live in! While that may not be precisely what is happening in this case, as far as I can tell I’m dealing with a bug in the Oracle library.

We were able to run like this (in production too) for quite some time before I found a solution, because everything in the script could run before the segfault occurred. However, the return code would always be nonzero (so scripts that properly checked return codes from CLI PHP scripts had to be modified), it would spam the kernel logs, and generally annoy myself and our developers. Also, OCI8 connections made through httpd and mod_php were unaffected as the PHP module and extensions get loaded into memory, but not unloaded during the normal course of execution.

My patch is not elegant but works fine:


--- Zend/zend_API.c.orig Wed Sep 12 12:40:21 2007
+++ Zend/zend_API.c Wed Sep 12 12:43:45 2007
@@ -1912,9 +1912,11 @@

#if HAVE_LIBDL || defined(HAVE_MACH_O_DYLD_H)
#if !(defined(NETWARE) && defined(APACHE_1_BUILD))
+/*
if (module->handle) {
DL_UNLOAD(module->handle);
}
+*/
#endif
#endif
}

which essentially stops PHP from calling dlclose(3) on modules when it is exiting. As far as I have tested this works just fine because PHP is exiting anyway, but I would not use this patch if the dlclose(3) was called normally during runtime without exiting immediately afterwards. If you care to apply this patch, I saved the above text in a file called patch-Zend::zend_API.c, placed it in /usr/ports/lang/php5/files, and rebuilt PHP by executing portupgrade -f php5. Ports will automatically patch zend_API.c appropriately, and you should be good to go. The system I tested all of this on:

FreeBSD 6.2-RELEASE-p6
PHP 5.2.3
oracle8-client-0.1.1_1

There are some other instructions out there but I have found no need for the instant client, nor can I see how the instant client is even used by PHP in the example given there. That means you don’t need the Linux compatibility module loaded into your FreeBSD kernel, a Linux base system, or any of Oracle’s instant client packages (which require registration to download anyway).

4 Responses to “FreeBSD + PHP + OCI8 segfault fix”

  1. Brian Janish Says:

    Gordon,

    I ran across your blog today looking for a good recipe to get an Oracle connector working with the same versions of FreeBSD and PHP that you mention. Do you have a step-by-step process setup that I could see? I’m under the gun here am looking everywhere for help.

    Thanks ahead of time,

    Brian Janish


  2. Gordon,

    I placed a bug report with FreeBSD and found that our issues with the segfault are related to bug http://www.freebsd.org/cgi/query-pr.cgi?pr=103271&cat=kern . I was able to verrify this by disabling pspell.so in the extensions.ini file.

    Thought I’d share this with you.

  3. Gordon Says:

    Interesting. The servers that experience this don’t actually have the pspell.so extension installed, but the same symptoms occur with the oci8.so extension as with the pspell.so extension. I’d be curious to see if the newer GCC version fixed the issue with oci8.so as well. I’ll let the current admin of the boxes know.

    Thanks for the bug report and letting me know!

  4. Marat Says:

    I’ve have FreBSD 5.3 Apache20 PHP 5.2.5 oracle8-client-0.2.0_1 and I segfaults as mentioned in the article, but I don’t have suhosin.so and pspell.so. I’ve suhosin patch on my PHP.
    How are suhosin/pspell extensiion bugs, and segfaults in oracle interaction in PHP related?


Leave a Reply