PHP Segmentation fault. Сдаюсь.

zIs

Новичок
Такая ситуация.
Есть демон на php, который в бесконечном цикле читает сокет через socket_read(). И иногда падает. Никаких ошибок php нет. Перерасхода памяти нет.
Просто падает, кидая в syslog убунты сообщение типа:
kernel: [5075639.694855] php[9830]: segfault at 7f6125f4a809 ip 00000000006b51c9 sp 00007fff9e798ea0 error 4 in php5[400000+70d000]
Версия Убунты стабильная, php, соответственно тоже: PHP 5.3.2-1ubuntu4.7 with Suhosin-Patch (cli)

Может раз в минуту падать, может раз в 8 часов. Закономерности не выявил.
Когда поток данных небольшой, почти не падает.

На сервере крутится живой проект, больше ничего не падает.

Подскажите, куда копать? Как узнать, на какой строке падает?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
куда копать - никто не скажет, нужен воспроизводимый алгоритм
судя по зависимости от трафика, идет переполнение какого-то буфера,
но ошибка это php или ты неправильно работаешь с сокетами - кто знает

можно попробовать обновить php, собрать без сухосина
как вариант, можно собрать в другом каталоге php в режиме дебага и запустить демон в нем, чтобы получить core dump, из которого что-нибудь будет понятно
 

zIs

Новичок
Буду пробовать. Кстати, при одинаковых записях в syslog, php всё-таки иногда (но не всегда) выкидидывает в поток ошибок "zend_mm_heap corrupted".
А это к чему может относиться?
Из оптимизаторов стоит APC
 

tz-lom

Продвинутый новичок
А нужен ли вообще кешер опкода для демона?
 
  • Like
Реакции: AmdY

AmdY

Пью пиво
Команда форума
tz-lom
поддерживаю, только подозреваю что apc и так стоит, но не для cli
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
для cli в apc по дефолту выключен кеш байт-кода
 

zIs

Новичок
был включен. теперь выключен. только ничего не изменилось)
а в принципе, к чему стоит склоняться - баг php или мой код кривой?
 

AmdY

Пью пиво
Команда форума
zIs
а как мы догадаемся что у тебя за код и где он падает. сделай лог, ищи места где падает.
 

tony2001

TeaM PHPClub
1) проапгрейдить PHP
2) отключить кэш опкода
3а) сделать короткий самодостаточный кусок кода
если совсем-совсем не получается, то
3б) получить корку - см. "Generic way to get a core on Linux" http://bugs.php.net/bugs-generating-backtrace.php
но для этого лучше всего использовать PHP собранный с дебагом.
 

fixxxer

К.О.
Партнер клуба
если совсем-совсем не получается, то
3б) получить корку
не, надо 3а.

по 3б - например у меня таких кило про gc. я даже не репорчу, потому что понимаю, что толку ноль, и по такой инфе ничего не исправишь. да и аналогичные репорты уже года три висят
 

fixxxer

К.О.
Партнер клуба
Гм. А он (apc) может на это влиять при cli sapi и apc.enable_cli => Off?

Бэктрейс такой

(gdb) bt
#0 0x0000000000566687 in zval_scan_black ()
#1 0x0000000000566869 in zval_scan ()
#2 0x0000000000566e5c in gc_collect_cycles ()
#3 0x000000000055a69d in zif_gc_collect_cycles ()
#4 0x00000000005970f7 in zend_do_fcall_common_helper_SPEC ()
#5 0x000000000056dcc3 in execute ()

Кейс - долгоживущая фигня, цикл по сути вида
while (1) {
check_and_fork_child_if_needed();
handle_signals();
gc();
}

Но там есть некоторые навороты. В простейшем виде воспроизвести не удалось.
 

tony2001

TeaM PHPClub
это проблема APC.
где-то он там разрушает звалы, которые потом подпадают под GC.

я это 'исправил" примерно так: http://dev.daylessday.org/diff/gc_removed.diff =)
ну и отключил нафиг GC - у меня не демоны долгоиграющие, а скрипты вида упал-отжался.
и по пути перешел на eAcc своей модели - https://github.com/tony2001/eaccelerator/tree/alt
 

fixxxer

К.О.
Партнер клуба
опа. нюанс

на одном из серверов где это проявляется вообще нет акселератора :D
 

tony2001

TeaM PHPClub
прям новый PHP без акселератора и всё равно такое есть?
и бэктрэйс такой же "содержательный"?
 

fixxxer

К.О.
Партнер клуба
не совсем последний. 5.3.5.
без акселераторов, да.

корки старые валяются, мне это все надоело, и я gc тупо вырубил :)

проверю на снэпшоте как время будет, но вроде там не менялось ничего в этих местах на первый взгляд

хотя понятно что zval-ы побиться могли чем угодно, да =) проверю в общем
 

tony2001

TeaM PHPClub
>корки старые валяются, мне это все надоело, и я gc тупо вырубил
и после этого работает?
стОит попробовать на новом PHP, если всё еще проявляется - дай мне знать, я передам Стогову, это его епархия.
 

zIs

Новичок
Поставил последний PHP без suhosin.
Раньше при segfault в daemon.log писалось "killed by SEGV signal".
Теперь про segmentation fault больше ничего не вижу. Возможно, даже падения стали реже.
Но падает так же без ошибок PHP, а в daemon.log пишет "terminated with status 65".

Нашёл что 65 - это EX_DATAERR /* data format error */

Логгированием обнаружил, что чаще всего падает при обработке сообщений определённого типа.

Получает вот такой XML:
PHP:
<Odds active="1" changed="true" combination="0" freetext="Correct score flex" id="1806497" specialoddsvalue="4:0" subtype="104" type="ftnw"
	typeid="8">
	<OddsField active="1" type="4:0">2.4</OddsField>
	<OddsField active="1" type="5:0">2.85</OddsField>
	<OddsField active="1" type="6:0">9.5</OddsField>
	<OddsField active="1" type="7:0">64.0</OddsField>
	<OddsField active="1" type="8:0">75.0</OddsField>
	<OddsField active="1" type="9:0">75.0</OddsField>
	<OddsField active="1" type="10:0">75.0</OddsField>
	<OddsField active="1" type="4:1">10.25</OddsField>
	<OddsField active="1" type="5:1">21.0</OddsField>
	<OddsField active="1" type="6:1">53.0</OddsField>
	<OddsField active="1" type="7:1">75.0</OddsField>
	<OddsField active="1" type="8:1">75.0</OddsField>
	<OddsField active="1" type="9:1">75.0</OddsField>
	<OddsField active="1" type="4:2">75.0</OddsField>
	<OddsField active="1" type="5:2">75.0</OddsField>
	<OddsField active="1" type="6:2">75.0</OddsField>
	<OddsField active="1" type="7:2">75.0</OddsField>
	<OddsField active="1" type="8:2">75.0</OddsField>
	<OddsField active="1" type="4:3">75.0</OddsField>
	<OddsField active="1" type="5:3">75.0</OddsField>
	<OddsField active="1" type="6:3">75.0</OddsField>
	<OddsField active="1" type="7:3">75.0</OddsField>
	<OddsField active="1" type="4:4">75.0</OddsField>
	<OddsField active="1" type="5:4">75.0</OddsField>
	<OddsField active="1" type="6:4">75.0</OddsField>
	<OddsField active="1" type="4:5">75.0</OddsField>
	<OddsField active="1" type="5:5">75.0</OddsField>
	<OddsField active="1" type="4:6">75.0</OddsField>
</Odds>
и парсит его с помощью SimpleXml (все XML заведомо маленького объёма)

падает где-то на этом участке кода:
прошу прощения, точнее не смог написать, потому что даже для определения этого участка пришлось глазами "пропарсить" 200 мб логов.
из кода вырезал всё лишнее.

PHP:
$xml = simplexml_load_string($xml);
foreach ($xml->Odds as $odds) {
  $odds_id = (string)$odds['id'];
  if (!isset($this->odds["$event_id"]))
    $this->odds["$event_id"] = array();
  if (!isset($this->odds["$event_id"]["$odds_id"]))
    $this->odds["$event_id"]["$odds_id"] = array();
  $cur_odds = $this->odds["$event_id"]["$odds_id"];

  if (isset($odds['specialoddsvalue'])) {
    $special = (string)$odds['specialoddsvalue'];
  } else
    $special = '';


  /*
  Падает где-то в этом цикле, обарботав несколько OddsField. 
  Падает изредка, системы не заметил. 
  */
  foreach ($odds->OddsField as $odd) {

    $odd_type = (string)$odd['type'];

    if (!isset($cur_odds["$odd_type"])) {

      ## пробуем найти ее в базе
      $q = OddTable::getInstance()->createQuery('o')
        ->where('o.event_id = ?', $event_id)
        ->andWhere('o.type = ?', $NL_type_id)
        ->andWhere('o.outcome = ?', $odd_type);
      if ($special !== '')
        $q->andWhere('o.special = ?', $special);


      if (!$sth = $q->fetchOne()) {

        $cur_odds["$odd_type"] = new Odd();
        $cur_odds["$odd_type"]->setEventId($event_id);
        $cur_odds["$odd_type"]->setType($NL_type_id);
        $cur_odds["$odd_type"]->setOutcome($odd_type);
        $cur_odds["$odd_type"]->setSpecial($special);
      } else {
        $cur_odds["$odd_type"] = $sth;
      }
    } else {
      $cur_odds["$odd_type"]->setOutcome($odd_type);
      $cur_odds["$odd_type"]->setSpecial($special);
    }

    if (((int)$odds['active']) && ((int)$odd['active'])) {

      $cur_odds["$odd_type"]->setValue((float)$odd);
      $cur_odds["$odd_type"]->setIsActive(1);
    } else {
      $cur_odds["$odd_type"]->setIsActive(0);
    }

    try {
      $cur_odds["$odd_type"]->save();
    } catch (Exception $e) {
      echo $e->getTraceAsString();
      throw $e;
    }

    $this->odds["$event_id"]["$odds_id"] = $cur_odds;
  }
}
Комменты к коду:
Конструкции типа $odds["$event_id"]["{$odds['id']}"] с ключами в кавычках использую специально, потому что иначе PHP пытается делать интовые ключи, а это не всегда приводит к хорошим последствиям с этими данными.
 
Сверху