[Moscow.pm] Баг в JSON::XS?

Eugene Ponizovsky ponizovsky на gmail.com
Пт Янв 30 04:46:47 PST 2015


Приветствую.

Вот еще столкнулся со странным поведением JSON::XS (3.01).

Пытаюсь сериализовать объект, содержащий объекты, используя функцию FREEZE. Один из объектов содержит большое число аргументов (61 пара ключ-значение). При сериализации такого объекта скрипт падает с ошибкой "Segmentation fault" или метод encode() возвращает undef.

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

Cpanel::JSON::XS ведет себя также. Ошибка проявляется на разных машинах и OS (Linux, FreeBSD, OS X).

Пример:

#!/usr/bin/env perl

use 5.010000;
use strict;
use warnings;

use JSON::XS;

my $json_szr = JSON::XS->new();
$json_szr->allow_tags( 1 );

my @foo_params;
for ( 1 .. 61 ) {
  push ( @foo_params, "coo$_" => 1 );
}
my $foo1 = Foo->new( @foo_params );
my $foo2 = Foo->new( @foo_params );

my $bar1 = Bar->new(
  foo => $foo1,
);

my $bar2 = Bar->new(
  foo => $foo2,
  bar => $bar1
);

my $bar_json = $json_szr->encode( $bar2 );
if ( defined $bar_json ) {
  say $bar_json;
}


package Foo;

####
sub new {
  my $class = shift;
  my %params = @_;
 
  return bless \%params, $class;
}

####
sub FREEZE {
  my $self = shift;
  
  return %{$self};
}

####
sub THAW {
  my $class = shift;
  my $szr   = shift;

  return $class->new( @_ );
}


package Bar;

####
sub new {
  my $class = shift;
  my %params = @_;
 
  return bless \%params, $class;
}

####
sub FREEZE {
  my $self = shift;
  
  return %{$self};
}

> 29 нояб. 2014 г., в 10:42, TheAthlete <theathlet на yandex.ru> написал(а):
> 
> Согласен, что перекрывает, но здесь JSON::XS создан с методом
> convert_blessed, который говорит, что переданный обхект должен иметь метод
> TO_JSON. Объект модуля boolean имеет данный метод.
> 
> $  perl -MData::Printer -MCpanel::JSON::XS -Mboolean=-truth -E '$j =
> Cpanel::JSON::XS->new->convert_blessed; $b = (0 == 1); say
> $j->encode({false => $b}); p$b'
> {"false":false}
> boolean  {
>      Parents       Exporter
>      public methods (9) : boolean, false, import, isBoolean, isFalse,
> isTrue, TO_JSON, true, truth
>      private methods (1) : __ANON__
>      internals: 0
> }
> 
> $  perl -MData::Printer -MJSON::XS -Mboolean=-truth -E '$j =
> JSON::XS->new->convert_blessed; $b = (0 == 1); say $j->encode({false =>
> $b}); p $b'
> Modification of a read-only value attempted at -e line 1.
> 
> Насколько я понял, эта ошибка связана с приведением к строке булевых
> значений (Boolean stringify) в модуле boolean.
> 
> Данная ошибка была скорее всего исправлена в Cpanel::JSON::XS начиная с версии 2.3311 -
> https://github.com/rurban/Cpanel-JSON-XS/commit/a42d7b7ec05c9aad18ba9b0ef12c721c31a47317 <https://github.com/rurban/Cpanel-JSON-XS/commit/a42d7b7ec05c9aad18ba9b0ef12c721c31a47317>
> 
> Victor Efimov <victor на vsespb.ru <mailto:victor на vsespb.ru>> писал(а) в своём письме Fri, 28 Nov 2014
> 20:44:50 +0300:
> 
>> 28 ноября 2014 г., 18:41 пользователь TheAthlete <theathlet на yandex.ru> написал:
>>> Неделя багов в JSON::XS! :)
>> 
>> Почему это баг JSON::XS ?
>> 
>> use strict; use warnings;
>> use Test::More tests => 3;
>> use boolean -truth;
>> use JSON::XS;
>> my $json = JSON::XS->new;
>> is($json->encode({"hey" => !!0}), 'abc',  'JSON false works');
>> 
>> тоже фейлится. если
>> 
>> use boolean -truth;
>> 
>> закоментировать, то работает норм.
>> 
>> Это потому что опция
>> 
>> -truth
>> 
>> You can specify the -truth option to override truth operators to
>> return boolean values.
>> 
>> use boolean -truth;
>> print ref("hello" eq "world"), "\n";
>> 
>> 
>> перекрывает операторы Perl, чтобы они возвращали объект. Почему
>> считается что JSON::XS должен с этим работать ? Почему это не баг в
>> "boolean" ?
>> 
>> 
>>> Тоже столкнулся с багом в JSON::XS - при установке модуля boolean, который
>>> в зависимостях у Test::DBIx::Class, не был пройден тест json.t.
>>> Заглянув в issue данного модуля на github, нашел такой тикет:
>>> 
>>> json.t fails on many Linux systems -
>>> https://github.com/ingydotnet/boolean-pm/issues/5
>>> 
>>> Там некоторые советуют установить Cpanel::JSON::XS - установил и все
>>> заработало, хотя не у всех падает при установленном JSON::XS.
>>> 
>>> Если модифицировать тест:
>>> 
>>> use strict; use warnings;
>>> use Test::More tests => 3;
>>> use boolean -truth;
>>> my $HAVE_JSON = eval { require JSON::MaybeXS };
>>> SKIP: {
>>>      skip "JSON is missing", 3 unless $HAVE_JSON;
>>>      eval{
>>>          my $json = JSON::MaybeXS->new->convert_blessed();
>>>          is($json->encode({false => (0 == 1)}), '{"false":false}',
>>>              'JSON false works');
>>>        is($json->encode({true  => (1 == 1)}), '{"true":true}',
>>>            'JSON true works');
>>>        is(ref(boolean::TO_JSON(true)), 'SCALAR',
>>>            'Make sure we can call boolean::TO_JSON($b)');
>>>        }
>>> };
>>> 
>>> в следующий:
>>> 
>>> use strict; use warnings;
>>> use Test::More tests => 3;
>>> use boolean -truth;
>>> my $HAVE_JSON = eval { require JSON::XS };
>>> SKIP: {
>>>      skip "JSON is missing", 3 unless $HAVE_JSON;
>>>      my $json = JSON::XS->new->convert_blessed();
>>>      is($json->encode({false => (0 == 1)}), '{"false":false}',
>>>        'JSON false works');
>>>      is($json->encode({true  => (1 == 1)}), '{"true":true}',
>>>        'JSON true works');
>>>      is(ref(boolean::TO_JSON(true)), 'SCALAR',
>>>        'Make sure we can call boolean::TO_JSON($b)');
>>> };
>>> 
>>> и запустить, то тест сваливается с ошибкой "Modification of a read-only
>>> value attempted at test/json.t line 9"
>>> 
>>> Если заменить на Cpanel::JSON::XS или JSON::PP, то все ок
>>> 
>>> Вадим Власов <scripter.vrn на gmail.com> писал(а) в своём письме Wed, 26 Nov
>>> 2014 20:01:33 +0300:
>>> 
>>>> Исследуя новый сериализатор в JSON::XS наткнулся:
>>>> 
>>>> $ echo 'use strict;
>>>> use warnings;
>>>> use feature "say";
>>>> 
>>>> use JSON::XS;
>>>> my $j=JSON::XS->new->allow_tags;
>>>> 
>>>> say "JSON::XS: $JSON::XS::VERSION";
>>>> say "Types::Serialiser: $Types::Serialiser::VERSION";
>>>> 
>>>> my $t = $j->encode( Foo->new );
>>>> say $t;
>>>> 
>>>> my @t = $j->encode( Foo->new );
>>>> 
>>>> package Foo;
>>>> sub new { bless {}, $_[0]; }
>>>> sub FREEZE { ( 123, 456 ); }' | perl
>>>> *JSON::XS: 3.01*
>>>> *Types::Serialiser: 1.0*
>>>> *("Foo")[123,456]*
>>>> *panic: attempt to copy freed scalar c37a18 to c37a00 at - line 14.*
>>>> 
>>>> $ perl -MJSON::XS -wE 'say JSON::XS->new->allow_tags->encode( bless {},
>>>> Foo
>>>> ); package Foo; sub FREEZE{ return 123 }'
>>>> *Use of uninitialized value in say at -e line 1.*
>>>> *("Foo")[123]*
>>>> 
>>>> $ perl -MJSON::XS -wE 'say scalar( JSON::XS->new->allow_tags->encode(
>>>> bless
>>>> {}, Foo )); package Foo; sub FREEZE{ return 123 }'
>>>> *("Foo")[123]*
>>>> 
>>>> Проверили на разных машинах и на разных версиях perl-а - одно и то же.
>>>> 
>>> 
>>> 
>>> --
>>> Написано в почтовом клиенте браузера Opera: http://www.opera.com/mail/
>>> 
>>> --
>>> Moscow.pm mailing list
>>> moscow-pm на pm.org | http://moscow.pm.org
> 
> 
> -- 
> Написано в почтовом клиенте браузера Opera: http://www.opera.com/mail/ <http://www.opera.com/mail/>
> -- 
> Moscow.pm mailing list
> moscow-pm на pm.org <mailto:moscow-pm на pm.org> | http://moscow.pm.org <http://moscow.pm.org/>
----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mail.pm.org/pipermail/moscow-pm/attachments/20150130/44bb720e/attachment-0001.html>


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