Вопрос по exception, php – Сбит с толку: PHP фатальная ошибка: исключение, выбрасываемое без фрейма стека в поле Unknown в строке 0?

32

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

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

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

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

ОБНОВЛЕНИЕ / ПРИМЕЧАНИЕ: я на самом деле не могу воспроизвести ошибку самостоятельно, только вижу, что это происходит в журналах, см. Ниже параграф, где я Верю ошибка происходит ...

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

<code>} 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));
}
</code>

Буду очень признателен за подсказки!

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

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

<code># ./httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c
</code>
Ты выбрасываешь исключение из деструктора? DampeS8N
Ну тогда попробуй найти сходство. В начале каждого полученного вами запроса запишите текущую временную метку и print_r (get_defined_vars ()) в файл журнала. Или еще лучше: пустьtcpflow работает, чтобы у вас был полный дамп заголовков http. Затем попытайтесь определить правильный файл журнала и положение в файле журнала по отметке времени при возникновении ошибки в журнале ошибок. Восстановите точный заголовок http-запроса и отправьте его на свой сервер. Может быть, это поможет вам воспроизвести. yankee
Можете ли вы воспроизвести это надежно? Если это так, я бы попробовал запустить нарушающий код за пределами веб-сервера, если это возможно, или под чем-то базовым, например CGI. Я смутно помню, что у меня была эта ошибка, и это было связано с MPM, на котором я работал с PHP. halfer
@ янки, ты мужчина !! Определил это, используя вывод журнала ... Была параSimpleXMLElements хранятся в сессии. Но уловка в том, что это случится только при посещении с IP, которого никогда не было раньше, поэтому я не заметил бы ни одного из моих собственных запросов, вызывающих его !! С нетерпением жду возможности попробовать tcpflow в какой-то момент .... Теперь я не вижу опции "Начать награду" снова, знаете ли вы, есть ли другой способ, которым я могу наградить вас больше очков (имел 50 повторений) щедрость, которая не пополнилась)? Хотели бы вы создать ответ, который я тогда приму? groovenectar
@ DampeS8N, я уверен, что в деструкторе нет кода исключения, приложение действительно не использует слишком много деструкторов, если вообще .. groovenectar

Ваш Ответ

11   ответов
18
Проблем

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

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

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

Скорее всего, этого достаточно, если вы знаете все параметры POST / GET. Если вы не можете воспроизвести только эти, вам нужно знать дополнительные заголовки запроса. Например, пользовательский агент, accept-encoding, ... Если вы все еще не можете воспроизвести, тогда это становится очень трудным: ошибка может зависеть от состояния (сеанса), текущего времени, 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. Надеемся, что количество запросов в секунду невелико, так что вы все равно сможете идентифицировать запрос. Возможно, некоторые дополнительные параметры в журнале ошибок, такие как source ip, помогут вам идентифицировать запрос (если ваш журнал ошибок показывает это). Из этих данных восстановите запрос с теми же параметрами POST / GET.

Метод tcpdump

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

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

Делать больше вещей

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

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

Спроси пользователя

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

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

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

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

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

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

4

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

Примечание: ... Неизвестно в строке 0 - Как найти правильную строку, это НЕ "строка 0"

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

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

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

Отличная идея! Я попробую как можно скорее и сообщу ... groovenectar
Штопать! Я положил это в верхней части сценария инициализации:function my_exception_handler($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)); } set_exception_handler('my_exception_handler'); Проверено, что он ловит исключения, и всего несколько минут назад пришел другой![Mon May 21 09:48:39 2012] [error] [client x.x.x.x] PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0 Я тоже очень на это рассчитывал .. groovenectar
2

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

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

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

Argggh! Я действительно ненавижу этот регистронезависимый / сенситив, я проблема: twilson
2

тов SimpleXML.

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

Д:

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

Посл:

$token = (string) $response->Token->Value;
  /* token saved in session, no error */
Это было давно, но я думаю, что и здесь тоже было так. groovenectar
0

оказалось, что сервер обновляется с 5 до 6, а PHP - с 5,4 до 5,3. Фактическая проблема была PHP APC, не настроен должным образом. Проверьте свой APC. Я использовал Symfony2, так что вы можете найти помощь наSymfony Невозможно выделить память для пула

2

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

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

// 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 (). Что я забрал из опыта это:

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

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

Так как бы я отследил это, зная, что я знаю сейчас? Поскольку я не знаю какого-либо способа проверки «стека» обработчика ошибок PHP, я думаю, что может иметь смысл использовать объект Singleton для инкапсуляции всех операций set / restore для обработчиков ошибок PHP. По крайней мере, тогда можно будет проверить состояние Singleton перед обычным выходом из программы, и если обнаружатся «висячие» обработчики ошибок, чтобы сгенерировать разумное сообщение об ошибке / предупреждении до того, как PHP сойдет с ума.

0

Один простой способ вызвать эту ошибку - старый сервер с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 - ошибка. похоже, что существует конфликт между экземпляром класса и переменной (сеанс).
По крайней мере, так я получил эту досадную ошибку, которую так сложно отладить.

0

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

0

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

0

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

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

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

Похожие вопросы