<rmcreative>

RSS

PHP и юникод в стрэктрейсе

12 марта 2012

Какое-то время назад creocoder наткнулся на ????? вместо значения параметра в логах ошибок Yii. После анализа проблемы стало ясно, что нашёлся баг в PHP.

Exception::getTraceAsString и Exception::__toString не работают с юникодом в значениях параметров при построении stacktrace. В результате для

<?php
function test($arg){
    throw new Exception();
}
 
try {
    test('тест');
}
catch(Exception $e) {
    echo $e->getTraceAsString();
    echo (string)$e;
}

получаем

d:\web\usr\local\php54>php.exe d:\src\exception_wrong_trace\test.php
#0 D:\src\exception_wrong_trace\test.php(7): test('????')
#1 {main}exception 'Exception' in D:\src\exception_wrong_trace\test.php:3
Stack trace:
#0 D:\src\exception_wrong_trace\test.php(7): test('????')
#1 {main}

Обойти можно собрав строку руками на основе массива, полученного через Exception::getTrace.

В Yii пока решили это не фиксить. Заслал баг на php.net.

Комментарии RSS

  1. №6043
    Максим
    Максим 12.03.2012, 23:04:37

    Проблема очень старая на самом деле, но никогда не думал о ней как о баге....

  2. №6044
    Михайловский Василий
    Михайловский Василий 13.03.2012, 7:00:40

    Можно использовать $e->getTrace()

    Проблема именно в преобразовании тейса в строку. ./Zend/zend_exceptions.c, метод _build_trace_args:

    case IS_STRING: {
            int l_added;
            TRACE_APPEND_CHR('\'');
            if (Z_STRLEN_PP(arg) > 15) {
                    TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
                    TRACE_APPEND_STR("...', ");
                    l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
            } else {
                    l_added = Z_STRLEN_PP(arg);
                    TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
                    TRACE_APPEND_STR("', ");
                    l_added += 3 + 1;
            }
            while (--l_added) {
                    if ((*str)[*len - l_added] < 32) {
                            (*str)[*len - l_added] = '?';
                    }
            }
            break;
    }
    
  3. №6045
    Sam
    Sam 13.03.2012, 13:48:29

    О, может сразу в тикет отписаться?

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.