Озадаченный: PHP фатальная ошибка: исключение, брошенное без кадра стека в неизвестной строке 0?

я обнаружил, что одной из распространенных причин ошибки является исключения из обработчика исключений. Я совершенно уверен, что этого не происходит в приложении, которое я пытаюсь отладить... Но я поместил все строки обработки инициализации в начало индекса.php в try / catch.*

это, по-видимому, также может произойти, потому что некоторые вещи не могут быть сериализованы для хранения в сеансе. Самое большее, это приложение хранит массивы в сеанс (совсем немного), но я уверен, что он не хранит в нем ничего слишком необычного.

кто-то прокомментировал, что это произошло с ними, потому что их первичный ключ должен быть CHAR (32) вместо INT(11). ПК в этом приложении все INTs.

другие предложения, что это может быть проблема с PHP 5.3.3 исправлена в 5.3.6, полный диск и нужно напечатать SimpleXML значение. Мы запускаем PHP 5.3.3, но в этом случае обновление должно быть последним средством. Так было не всегда.

UPDATE / NOTE: я на самом деле не могу воспроизвести ошибку сам, только вижу, что это происходит в журналах, см. ниже абзац, где я верить ошибка происходит...

* из журналов ошибок кажется вероятным, что по крайней мере одно место, где это происходит, является индексом.РНР. Я делаю этот вывод только потому, что он указан. в некоторых записях в адреса. Код try/catch в настоящее время находится только вокруг "верхней" части инициализации скрипта, ниже которой в основном выводится HTML. В выходных данных есть некоторый PHP-код (довольно простой материал), поэтому мне может потребоваться проверить это. Вот часть catch, которая не производит никакого вывода в журналах:

} catch (Exception $e) {
    error_log(get_class($e)." thrown. Message: ".$e->getMessage(). "  in " . $e->getFile() . " on line ".$e->getLine());
    error_log('Exception trace stack: ' . print_r($e->getTrace(),1));
}

был бы очень признателен за любые советы по этому поводу!

EDIT: PHP работает как модуль Apache (API сервера: Apache 2.0 Дрессировщик.) Я не думаю, что есть какие-либо ускорители PHP в использовании, но это может быть просто, что я не знаю, как сказать. Никто из них перечислены в Википедии в функцию phpinfo().

насколько я могу судить, MPM является prefork. Это первый раз, когда я заглянул в MPM:

# ./httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

11 ответов


проблема

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

воспроизвести проблему

поскольку вы уже устранили общие причины, вам нужно будет воспроизвести ошибку. Если вы знаете, какой параметр вызовет ошибку, это должно быть легко найти ошибку.

  • скорее всего, этого достаточно, если вы знаете все параметры POST/GET.
  • если вы не можете воспроизвести всего, вам нужно знать дополнительные заголовки запроса. Например, агент пользователя, принять кодирования,...
  • если вы все еще не можете воспроизвести, то это становится очень сложно: ошибка может зависеть от состояния (сеанса), текущего времени, IP-адреса источника или тому подобного.

пользовательский журнал метод

давайте начнем просто: чтобы получить все параметры, вы можете написать в самом начале затронутого php-файла что-то вроде:

file_put_contents("/path/to/some/custom_error_log", date()."\n".print_r(get_defined_vars(), true), FILE_APPEND | LOCK_EX);

Не забывайте, что файл custom_error_log должен быть доступен для записи в ваше php-приложение. Затем при возникновении ошибки в журнале ошибок найдите соответствующие строки в файле custom_error_log. Надеюсь, не так много запросов в секунду, чтобы вы все еще могли идентифицировать запрос. Возможно, некоторые дополнительные параметры в журнал ошибок, такой как исходный ip, может помочь вам идентифицировать запрос (если ваш журнал ошибок показывает это). Из этих данных реконструируйте запрос с теми же параметрами POST/GET.

метод tcpdump

следующий вариант, который также очень прост, но требует от вас корневого доступа на вашем целевом компьютере, - установить tcpflow. Затем создайте папку, компакт-диск в эту папку и просто запустите (как root) tcpflow "port 80". Опция (порт 80) является выражением фильтра pcap. Увидеть все вы можете сделай это, смотри man pcap-filter. Существует много того, что могут сделать эти выражения фильтра.

теперь tcpflow будет записывать все tcp-соединения на порту 80, восстанавливать полный обмен данными, объединяя пакеты, принадлежащие одному соединению, и сбрасывать эти данные в файл, создавая два новых файла на соединение, один для входящих данных и один для исходящих данных. Теперь найдите файлы для соединения, которое вызвало ошибку, снова на основе метки времени в журнале ошибок и последнего изменения временная метка файлов. Затем вы получаете полные заголовки http-запросов. Теперь вы можете полностью восстановить HTTP-запрос, включая установку той же accept-encoding, user-agent и т. д. Вы даже можете передать запрос непосредственно в netcat, воспроизводя точный запрос. Остерегайтесь, хотя некоторые аргументы, такие как sessionid, могут быть на вашем пути. Если php обнаруживает, что сеанс истек, вы можете просто перенаправить его на логин или что-то еще, что неожиданно. Возможно, вам придется обменяться такими вещами, как идентификатор сеанса.

издеваясь больше вещей

если ничто из этого не помогает, и вы не можете воспроизвести ошибку на своей машине, то вы можете попытаться высмеять все, что трудно высмеять. Например, IP-адрес источника. Это может сделать некоторые трюки необходимыми, но это возможно: вы можете подключиться к своему серверу с помощью ssh с опцией "-w", создавая туннельный интерфейс. Затем назначьте оскорбительный ip-адрес на свой собственный компьютер и установите правила маршрутов (route add host ) для использования туннеля для конкретного ip. Если вы можете подключить два компьютера непосредственно друг к другу, вы даже можете сделать это без туннеля.

не foget, чтобы издеваться над сессией, которая должна быть esiest. Вы можете прочитать все переменные сеанса, используя метод с print_r (get_defined_vars ()). Затем вам нужно создать сеанс с точно такими же переменными.

задать

другой вариант будет на самом деле спросить пользователя, что он делает. Возможно, вы можете выполнить те же шаги, что и он и может размножаться.

если ничего из этого не помогает

если ничего из этого не помогает... что ж... Тогда это становится очень трудно. IP-вещь уже маловероятна. Это может быть библиотека GEO-IP, которая вызывает ошибку на IPs из определенного региона, но все это довольно маловероятные вещи. Если ничто из вышеперечисленного не помогло вам воспроизвести проблему, то вы, вероятно, просто не нашли правильный запрос во всех данных, сгенерированных custom_log_file-call / tcpflow. Пытаться увеличьте свои шансы, получив более точную метку времени. Вы можете использовать microtime () в php в качестве замены date (). Проверьте свой веб-сервер, если вы можете получить что-то более точное, чем секунды в журнале ошибок. Напишите свою собственную реализацию "хвоста", что дает вам более точную метку времени... Снизить нагрузку на систему, так что вам не придется выбирать из такого же (попробуйте в другое время суток, нагрузка пользователей на разных серверах...)

круг проблемы, как только вы можете воспроизвести

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

расскажите нам, что вы нашли. Мне любопытно ;-).


У меня тоже была такая ошибка. Выяснилось, что я вернул объект sql в моем классе сеанса (который использовался session_handler) вместо того, чтобы возвращать ничего или, по крайней мере, не объект sql. Сначала посмотрите на свои методы _write и _read, если вы тоже возвращаете некоторые неправильные вещи.

обратите внимание: ... Unknown on line 0-Как найти правильную строку, это не "line 0"


вместо обертывания кода в блоке try/catch, что происходит при регистрации обработчика исключений? Очевидно, что ваш блок try/catch не ловит исключение, что приводит к ошибкам, зарегистрированным в Apache. Регистрируя обработчик, вы можете быть уверены, что любое необработанное исключение обрабатывается.

кроме того, если вы используете пространства имен в своем приложении, убедитесь, что вы пишете \Exception в своем блоке catch (или включаете класс Exception с помощью инструкции use).


Это может быть немного поздно, но одна проблема, которую я обнаружил при перемещении сайта с локального на удаленный сервер. Я использовал Concrete5 cms разработал мой сайт локально (windows 8 в xampp), а затем загрузил на удаленный сервер под управлением Cent 0S

Windows mysql по умолчанию не учитывает регистр и создает базу данных нижнего регистра. Как только это было загружено на удаленный сервер, я получил " исключение, брошенное без кадра стека в неизвестном в строке 0?"

затем я исправил дело с таблицами базы данных и мой сайт снова начали работать.


для нас эта ошибка была вызвана непреднамеренной сериализацией объектов SimpleXML.

Если вы используете объекты SimpleXML с 5.3.3, убедитесь, что вы отбрасываете значения узла на все, что вам нужно (например, string), если вы сериализуете значения в сеансе.

до:

  $token = $response->Token->Value;
  /* token saved in session, results in line 0 error */

после:

$token = (string) $response->Token->Value;
  /* token saved in session, no error */

Я понимаю, этот вопрос уже ответили, но я добавлю это, так как это может помочь кому-то:

мне удалось (непреднамеренно) создать ошибки без кадра стека из функции, которая использовала свой собственный обработчик ошибок для поддержания контроля выполнения при вызове потенциально "опасной" функции, например:

// Assume the function my_error_handler() has been defined to convert any
// PHP Errors, Warnings, or Notices into Exceptions.

function foo() {
    // maintain control if danger() crashes outright:
    set_error_handler('my_error_handler');

    try {
        // Do some stuff.

        $r = danger();
    } catch (Exception $e) {
        $r = 'Bad Stuff, Man!';
    }

    restore error_handler();
    return $r;
}

произойдет "неотслеживаемый сбой"в конце выполнения программы если логика В "сделать некоторые вещи" возвращается из foo () напрямую, минуя вызов restore_error_handler (). То, что я взял из опыта, таково:

  1. PHP поддерживает стек обработчиков ошибок, которые становятся глубже / выше с каждым вызовом set_error_handler().
  2. плохие вещи могут произойти, если вы нажмете обработчики ошибок в стек и не очистите после себя, прежде чем программа выйдет "нормально".

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

Итак, как бы я выследил это, зная, что я знаю сейчас? Поскольку я не знаю, как проверить обработчик ошибок PHP "стек" напрямую, я думаю, что имеет смысл использовать одноэлементный объект для инкапсуляции всех операций набора/восстановления для обработчиков ошибок PHP. По крайней мере, тогда можно было бы проверить состояние Синглтона перед выходом из программы нормально, а если "висячие" ошибка обработчики обнаруживаются создать разумный отказ/предупреждение до версии PHP глючит.


У меня была такая же ошибка, появилось обновление сервера с centos 5 до centos 6 и понижение PHP с 5.4 до 5.3. Фактической проблемой был PHP apc, не настроенный должным образом. Проверь свой БТР. Я использовал Symfony2, поэтому вы можете найти некоторую помощь в Symfony не удалось выделить память для пула


один простой способ, чтобы произвести эту ошибку-старый сервер с register_globals = On. тогда вам нужно всего две строки кода:

<?php
    $_SESSION["my_var"] = "string";
    $my_var = new MyClass(); //could be any class, i guess
?>

как только вы перезагрузите эту страницу один раз, вы получите Exception thrown without a stack frame in Unknown on line 0 - ошибка. похоже, существует конфликт между экземпляром класса и переменной (session).
по крайней мере, так я получил эту раздражающую ошибку, которую так трудно отладить.


У меня была полностью такая же ошибка. Очень пространственный случай: если вы подключаете крючок безымянной функции (закрытия) к точке крючка экземпляра объекта. После этого вы пытаетесь сериализовать этот объект.


эта проблема возникла для меня, когда я изменил пространство имен на несколько пакетов Symfony. Удаление файлов в каталоге кэша symfony Исправлена проблема.


вероятно, у вас есть поврежденная/несогласованная таблица в базе данных. Попробуйте сбросить базу данных. Если вы получаете ошибку, это время. Отремонтируйте эту таблицу, и проблема должна уйти.

именно по этой причине работает clean install. Чистая установка-это просто чистая.

mysqlcheck должен работать, но если он не показывает и проблема все еще делает выше.