Ещё один способ отстрелить себе ногу в Perl

от автора

Посмотрим на код:

use strict; use warnings;  sub mysub($$) {     my ($a, $b) = @_;     print "$a\n";     print "$b\n"; } my $x = undef; mysub($x && $x->[0] =~ /abc/, $x = []); 

Может ли mysub в качестве первого аргумента получить нечто, что в boolean контексте является истинной?

Казалось бы нет, ведь для этого $x должен быть ссылкой на массив, а его первый элемент должен содержать подстроку ‘abc’

Но оказалось, что может

$perl poc.pl ARRAY(0xdb6d48) ARRAY(0xdb6d48) 

В чём же дело?

  1. в Perl (как и во многих других языках) X && Y, в случае если X — false, возвратит не просто false (не выполняя Y), а возвратит сам X (который должен быть false)
  2. Все параметры в Perl передаются по ссылке, а не по значению.

Таким образом когда расчитывается первый аргумент

$x && $x->[0] =~ /abc/ 

$x является undef т.е. false, следовательно вместо первого аргумента передаётся сам $x,
когда расчитывается второй аргумент, $x присваивается значение [] (ссылка на пустой массив), таким образом когда начинает выполняться код mysub, оба аргумента
содежрат ссылку на $x (которая является пустым массивом)

Если кажется, что код выглядит не очень применимым на практике, то могу сказать что быг был найден в реальном коде unit теста:

ok( ($errors && ($errors->[0] =~ /My Exception/i)), "should catch exception $errors->[0]" ); 

(при этом срабатывает ещё одна замечательная фича перла Autovivification — если обратиться к $errors->[0] то $error->[0] создастся,
если $error был до этого undef)

ссылка на оригинал статьи http://habrahabr.ru/post/168559/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *