[Moscow.pm] Fwd: Почему меняется старое значение, хотя переменная локализирована?

Vladimir Timofeev vovkasm на gmail.com
Ср Янв 6 15:56:18 PST 2016


2016-01-07 6:19 GMT+03:00 Eugen Konkov <kes-kes на yandex.ru>:
> Спасибо! Очень много интересной информации вы мне дали. Пойду изучать...
> Не могли бы вы мне подсказать файл, в котором перл генерирует обком для goto?

Ну это просто. Все OP в файлах op*.c, так что ack 'pp_goto' op*.c и получаем...
pp_ctl.c:2768 OP(pp_goto)

А вот дальше... текст там забавный )))

>
>>Во втором случае никакой local работать не будет, вернее будет...
> local $DB::single = $DB::single +0; работал и работает отлично и в дебаг режиме тоже (см. ниже)

Ух ты, я и не знал ))
Интересно почему, но быстрый просмотр показал, что чтобы понять,
придётся много времени потратить, которого нет...
По идее магия для DB::single get/set очень простая, просто сохраняет
значения ещё и в глобальном массивчике PL_DBcontrol (там для каждой
переменной single, trace... по слоту). Хендлеры в конце mg.c, функции
Perl_magic_setdebugvar и Perl_magic_getdebugvar.

>
>>Мне кажется, что для хранения текущего состояния в своём дебаггере
> Как раз не текущее состояние было нужно, а n фреймов назад...
>
>
> У меня в дебагере что-то наподобие:
> sub sub {
>      local $DB::single =  $DB::single +0; # без 0 не работает :?
>      return &$DB::sub;
>  }
>
> Где-то внутри вызываемой функции с именем "$DB::sub" я делаю $DB::single = 0 и автоматом останавливаюсь на первом операторе вне этой функции. Т.е. для кода:
> sub t{ $DB::single = 0; }
> t();
> $x++; <<< останавливаюсь тут
>
> Останавливаюсь потому, что после того как отработает 'return  &$DB::sub' перл восстановит старое локализированное значение $DB::single в TRUE
> и вызовется DB::DB на первом опкоде после возврата, те. '$x++'
>
> Но если бы мы хотели выйти на 2 фрейма вверх?
> То нам нужно, чтобы старое локализированное значение $DB::single восстановилось в FALSE
>
> Как поменять старое локализированное значение? - Взять ссылку на него...
> Получается примерно такое:
> sub sub {
>      $#DB::stack = $DB::deep;
>      $DB::stack[-1] =  { single => \$DB::single };
>
>      local $DB::single =  $DB::single +0;
>      local $DB::deep =  $DB::deep +1;
>      return &$DB::sub;
> }
>
> sub t1 { $DB::stack[-1]{ single } =  0; $DB::single =  0; }  #DEEP 2
> sub t2 { t1(); $y++; }  # DEEP 1
> t2(); #DEEP 0
> $x++;
>
> Если бы мы шли в функцию t1 пошагово, то было бы локализировано 2 значения $DB::single, это единицы.
> [
>    { single => \1 }
>    { single => \1 }
> ]
>
> после выполнения t1 стэк выгледел был бы так:
> [
>    { single => \1 }
>    { single => \0 }
> ]
>
> Соответственно после выхода из t1 перл бы востанавливал в $DB::single не в  единицу, а в 0,   а это бы позволило нам выйти из t2 тоже и остановиться на $x++
>
> И теперь мне понятно (благодаря вашему объяснению), что из-за магии $DB::single, когда мы делаем ${ $DB::stack[-1]{single} } = 0, то меняются все значения в стеке, а не только указанное, т.е. получаем:
> [
>    { single => \0 }
>    { single => \0 }
> ]
>
> соответственно вываливаемся полностью из программы...

А не может ли быть того, что просто нет никакого стека там (в месте,
где хранится реальное значение и куда дебаггер смотрит) в слоте
PL_DBControl? ;-)

>
> Я предпологаю, что должна быть возможность через XS обойти магию и присвоить 0 в правильную ссылку. Не могли бы вы порекомендовать какие нибудь хорошие мануалы по XS?
>

Мысль на вскидку (не проверял). В XS API есть SvIV_nomg(sv), типа
возвращает iv из sv и не вызывает магию. Пример использования в той же
mg.c:Perl_magic_setdebugvar ну и вообще по коду перла этого добра
раскиданно в достатке.

>
> PS. Сейчас пока обхожусь костылём. Завожу переменную, в которой хранится значение на сколько уровней нужно поднятся и в sub DB::DB делаю
> sub DB {
>    if( $DB::level-- != 1 ) {
>        $DB::single =  0;
>        return;
>    }
> }
>
>
> Соответсвенно в t1:
> sub t1 { $DB::level =  2; $DB::single =  0; }
> Недостаток этого метода, наверное, небольшой проигрыш в скорости работы, по сравнению с "правильным" методом, но выбирать не приходиться (((

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

>
> PSS. Тут для наглядности и простоты примеров я изменял значения из DB:: прям в коде скрипта, но в боевом примере этого добиваюсь с помощью комманд дебагера s n r
>
> Вы писали 6 января 2016 г., 18:45:53:
>
> VT> Ну вот это уже интереснее )
>
> VT> Так вот:
> VT> 1. Без дебаггера, $DB::single обычный скаляр, с ним всё происходит как
> VT> надо (в вашем случае это был $DB::x,  об этом чуть ниже).
> VT> $ perl -MDevel::Peek -e'Dump($DB::single)'
> VT> SV = NULL(0x0) at 0x7f882b82dc60
> VT>   REFCNT = 1
> VT>   FLAGS = ()
>
> VT> 2. С подключенным дебаггером.
> VT> $ perl -MDevel::Peek -d -e'Dump($DB::single)'
> VT>   DB<1> c
> VT> SV = PVMG(0x7fc78a025460) at 0x7fc78a004a30
> VT>   REFCNT = 1
> VT>   FLAGS = (GMG,SMG,IOK,pIOK)
> VT>   IV = 0
> VT>   NV = 0
> VT>   PV = 0
> VT>   MAGIC = 0x7fc789c052e0
> VT>     MG_VIRTUAL = &PL_vtbl_debugvar
> VT>     MG_TYPE = PERL_MAGIC_debugvar(*)
>
> VT> Во втором случае никакой local работать не будет, вернее будет... в
> VT> штатном режиме (это можно увидеть, если вставить Dump в ваш код), но
> VT> толку нет, потому что к значениям из слотов SV не будет доступа,
> VT> вместо этого будет вызываться метод из VTBL магический, который...
> VT> возвращает актуальное значение. (это примерное объяснение, я редко
> VT> лазил в эту область и внимательно сейчас читать исходники нет ни
> VT> времени ни желания :-)
>
> VT> Всю магию, которую вешает дебаггер можно посмотреть в perl.c где-то в
> VT> р-не строки 4000, функция Perl_init_debugger. Соотвественно, те
> VT> символы, на которых магия могут работать не нормально: DB::single,
> VT> DB::trace, DB::signal.
>
> VT> Мне кажется, что для хранения текущего состояния в своём дебаггере,
> VT> можно использовать нормальные свои переменные в пакете DB, главное не
> VT> пересечься с уже используемыми перлом.
>
> VT> 2016-01-06 22:38 GMT+03:00 KES <kes-kes на yandex.ru>:
>>> Я извиняюсь. Упустил важный момент. Вот полный код:
>>> $ cat Devel/DB.pm
>>> package DB;
>
>
>>> sub DB::DB {
>>> }
>
>>> sub sub {
>>>     {
>>>         $DB::single = 7; my $x = \$DB::single;
>>>         print "Before: ". \$DB::single ." <<$x $$x\n";
>>>         local $DB::single = 0;
>>>         print "After: ". \$DB::single ." <<$x $$x\n";
>>>     }
>
>>>     return &$DB::sub;
>>> }
>
>>> 1;
>
>>> $ perl -d:DB -e 'sub t{} t()'
>
>>> $ perl -v
>>> This is perl 5, version 22, subversion 0 (v5.22.0) built for x86_64-linux
>
>>> PS. Думаю в ближайшее мне придется очень глубоко копнуть в исходники перл, т.к. в дебаг режиме шероховатость на шероховатости :`-(
>>> --
>>> Moscow.pm mailing list
>>> moscow-pm на pm.org | http://moscow.pm.org
>
>
>
> VT> --
> VT> Vladimir Timofeev <vovkasm на gmail.com>
>
>
>
> --
> С уважением,
>  Eugen                          mailto:kes-kes на yandex.ru
>



-- 
Vladimir Timofeev <vovkasm на gmail.com>


Подробная информация о списке рассылки Moscow-pm