1

I've been programming a site using:

  1. Zend Framework 1.11.5 (complete MVC)
  2. PHP 5.3.6
  3. Apache 2.2.19
  4. CentOS 5.6 i686 virtuozzo on vps
  5. cPanel WHM 11.30.1 (build 4)
  6. Mysql 5.1.56-log
  7. Mysqli API 5.1.56

The issue started here https://stackoverflow.com/questions/6769515/php-programming-seg-fault. In brief, php is giving me random segmentation-faults.

[Wed Jul 20 17:45:34 2011] [error] mod_fcgid: process /usr/local/cpanel/cgi-sys/php5(11562) exit(communication error), get unexpected signal 11
[Wed Jul 20 17:45:34 2011] [warn] [client 190.78.208.30] (104)Connection reset by peer: mod_fcgid: error reading data from FastCGI server
[Wed Jul 20 17:45:34 2011] [error] [client 190.78.208.30] Premature end of script headers: index.php

About extensions. When i compile php with "--enable-debug" flag, i have to disable this line:

zend_extension="/usr/local/IonCube/ioncube_loader_lin_5.3.so"

Otherwise, the server doesn't accept requests and i get a "The connection with the server was reset". It is possible that i have to disable eaccelerator too because of the same reason. I still don't get why apache gets running it some times and some others not:

extension="eaccelerator.so"

Anyway, after i get httpd running, seg-faults can occurr randomly. If i don't compile php with "--enable-debug" flag, i can get DETERMINISTICALLY a php crash:

<?php
class Admin_DbController extends Controller_BaseController
{
    public function updateSqlDefinitionsAction()
    {
        $db = Zend_Registry::get('db'); 
        $row = $db->fetchRow("SHOW CREATE TABLE 222AFI");
    }
}
?>

BUT if i compile php with "--enable-debug" flag, it's really hard to get this error. I must add some complexity to make it crash. I have to be doing many paralell requests for a few seconds to get a crash:

<?php
class Admin_DbController extends Controller_BaseController
{
    public function updateSqlDefinitionsAction()
    {
        $db = Zend_Registry::get('db');
        $tableList = $db->listTables();
        foreach ($tableList as $tableName){
            $row = $db->fetchRow("SHOW CREATE TABLE " . $db->quoteIdentifier($tableName));
            file_put_contents(
                DB_DEFINITIONS_PATH . '/' . $tableName . '.sql',
                $row['Create Table'] . ';'
            );
        }
    }
}
?>

Please notice this is the same script, but creating DDL for all tables in database rather than for one. It seems that if php is heavy loaded (with extensions and me doing many paralell requests) it's when i get php to crash.


About starting httpd with "-X": i've tried. The thing is, it is already hard to make php crash with --enable-debug. With "-X" option (which only enables one child process) i can't do parallel requests. So i haven't been able to create to proper debug backtrace: https://bugs.php.net/bugs-generating-backtrace.php

My concrete question is, what do i do to get a coredump?


root@GWT4 [~]# httpd -V
Server version: Apache/2.2.19 (Unix)
Server built:   Jul 20 2011 19:18:58
Cpanel::Easy::Apache v3.4.2 rev9999
Server's Module Magic Number: 20051115:28
Server loaded:  APR 1.4.5, APR-Util 1.3.12
Compiled using: APR 1.4.5, APR-Util 1.3.12
Architecture:   32-bit
Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/prefork"
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT="/usr/local/apache"
 -D SUEXEC_BIN="/usr/local/apache/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_LOCKFILE="logs/accept.lock"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

4 Answers 4

2

Getting a core dump involves setting the "core file size" rlimit to something non-zero for the process(es) you want to get core dumps from. Given that you're running PHP in FCGI, you don't really care about Apache itself, it's not segfaulting; you want to have a script to run ulimit -c unlimited then exec your FCGI server.

I like to have a separate scratch partition for cores, so if they get a bit big or unruly they don't cause disk fill problems elsewhere -- set /proc/sys/kernel/core_pattern to something like /var/cores/%e-%p.core.

2
  • I appreciate your answer, but i tested running a single php (compiled with --enable-debug) and i can't get the segfault. And the coredump of the script run under php without the --enable-debug compile flag is useless for debugging purposes. At least for internals php. Thank you any way, really. Jul 21, 2011 at 3:59
  • So don't run a single PHP, run many PHPs. You said in your question that you just needed to "add some complexity" to make it crash with --enable-debug. Adding "complexity" doesn't negate the ability of PHP to dump core.
    – womble
    Jul 21, 2011 at 4:05
0

Must you use ioncube_loader and eaccelerator? Regarding eaccelerator, their 5.3.x support has been spotty at best and most 5.3 users rely on APC (which will also work better via FCGI anyway.)

If you must use eaccelerator, are you doing a "make distclean" and then their standing INSTALL instructions (double-checking that the phpize you're loading is for 5.3.6 and not some remnant from a previous install)? I suspect that's the entire source of your coredumps and that Apache isn't the culprit at all.

1
  • Hi, this is happening without all those extensions loaded. I'm compiling this with easy apache. Jul 25, 2011 at 18:22
0

I found a temporary solution. This is ugly, but fits:

public function selectCmd($q){

$charsFrom = array("\\a", "\\t", "\\n", "\\v", "\\f", "\\r", "\\\\", "\\0", "\\\"", "\\\'", "\\b");
$charsTo = array("\a", "\t", "\n", "\v", "\f", "\r", "\\", "\0", "\"", "\'", "\b");

exec('echo ' . escapeshellarg($q) . ' | mysql' .
    ' -h ' . escapeshellarg($this->_config['host']).
    ' -u ' . escapeshellarg($this->_config['username']).
    ' -p' . escapeshellarg($this->_config['password']).
    ' ' . escapeshellarg($this->_config['dbname']), $output);

$colNames = explode("\t", array_shift($output));
foreach ($colNames as &$colName){
    $colName = str_replace($charsFrom, $charsTo, $colName);
}
unset($colName);

$rowSet = array();
foreach ($output as $line){
    $row = array();
    $rawRow = explode("\t", $line);
    for ($i = 0; $i < count($rawRow); ++ $i){
        $row[$colNames[$i]] = str_replace($charsFrom, $charsTo, $rawRow[$i]);
    }
    $rowSet[] = $row;
}
return $rowSet;

}

You'll need to replace $this->_config with a real connection array.

This script runs any SQL command which returns rows. For now is the solution i'm taking. If someone wishes to help me proactively i still have the sources. I'm also the guy who has the PHP seg-fault using PHPUnit with Zend (deterministically). I'm doing all this in my job, don't have the resources to test out of it. Thank you for your comprehension.

0

Not sure if it helps in this case, but I set only one children, find PID and then debug it with strace

strace -p PID

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .