Oct22

Segmentation fault

I experienced that sometimes, web applications partly break with the following apache error log:

$ cat /var/log/apache/error.log
[Thu Oct 22 11:54:39 2009] [notice] child pid 17157 exit signal Segmentation fault (11)
[Thu Oct 22 12:00:06 2009] [notice] child pid 17158 exit signal Segmentation fault (11)
[Thu Oct 22 12:02:47 2009] [notice] child pid 17191 exit signal Segmentation fault (11)
[Thu Oct 22 12:02:47 2009] [notice] child pid 17343 exit signal Segmentation fault (11)

Whenever that error occurred, the server response is empty. In my case, that issue mostly happens in ajax requests where the server response should be some XML snippets. But if the segfault occurs, the XML snippet is empty – the onliest hint I get is the log entry in /var/log/apache/error.log.

First thing I tried is to debug applications using Zend Debugger, but if the debugger was enabled and I step through the application, the error did not happen and the request finishes correctly. Because Google did not lead to an answer, I sat down and tried until I was able to reproduce the error with a simple PHP script:

session_start();
class A
{
    public function __construct()
    {
        echo "A::__construct()";
    }

    public function __destruct()
    {
        $_SESSION["MyObject"] = $this;
        echo "A::__destruct()";
    }

    public function __toString()
    {
        return "CLASS_A";
    }
}
new A();

First time I called this script via web browser all things are good. But the second time, I get an segmentation fault error in the apache log and the browser just displays nothing. Reason for that is that I try to store the current object in the session variable. When I do this the very first time, it work’s because $_SESSION[“MyObject”] is not defined. But for any further call, $_SESSION[“MyObject”] is defined with the current object and it will be undefined in order to assign the new value. Thus A::__destruct() is called a second time, where $_SESSION[“MyObject”] will be re-defined again. This results in a endless loop and ends up in a segmentation fault of the currently used worker thread of the apache webserver.
Note that in PHP 5.2 (and earlier?), there’s a Bug which causes a segmentation fault whenever a PHP function is called recursively more than a definit times. I tried to reproduced and got a segmentation fault after about 900000 recursions.
To do things right, we should check $_SESSION[“MyObject”] whether it contains the current object. Only if $_SESSION[“MyObject”] contains another object than the current, we can safely define another value!

session_start();
class A
{
    public function __construct()
    {
        echo "A::__construct()";
    }

    public function __destruct()
    {
        if($this !== $_SESSION["MyObject"])
             $_SESSION["MyObject"] = $this;
        echo "A::__destruct()";
    }

    public function __toString()
    {
        return "CLASS_A";
    }
}
new A();

Storing objects in session variables brings another issue: The destructor of each object stored in the session is called each time, the current script ends. But the constructor is never called, because the initialized object already exists in the session. In order to avoid the destructor call, I recommend to serialize the object by using serialize() before storing it in the session:

session_start();
class A
{
    public function __construct()
    {
        echo "A::__construct()";
    }

    public function __destruct()
    {
        $_SESSION["MyObject"] = serialize($this);
        echo "A::__destruct()";
    }

    public function __toString()
    {
        return "CLASS_A";
    }
}
new A();

In order to access the serialized object, you should unserialize the object first by using unserialize(). Please note, that no every object property can be serialized and should be handled separately. You can use PHP’s magic methods like __sleep() or __wakeup() to handle those properties.

Leave a Reply

You must be logged in to post a comment.