Skip Menu |

This queue is for tickets about the RPC-XML CPAN distribution.

Report information
The Basics
Id: 41063
Status: resolved
Priority: 0/
Queue: RPC-XML

People
Owner: rjray [...] blackperl.com
Requestors: PEPL [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.64
Fixed in: 0.69



Subject: RPC::XML goes into deep recursion with cyclic references
When passed a cyclic data structure RPC::XML::(struct|array)::new will go into deep recursion with RPC::XML::smart_encode() which consequently will eat up all memory. Cyclic data structures are rather common - E.g. every DBIx::Class related object instance includes them. Pseudo Code to reproduce the problem: my $rs = $db->resultset('Some::Schema'); my $search_result = $rs->search({ amount => { '<', $value }, })->first(); # $search_result will hold cyclic references and the process will # start to eat up all cpu and mem resources... my $type = RPC::XML::struct->new($search_result); Potential approaches to fix this: * Check for cyclic references in the data structures passed * Allow to specify and enforce a maximum recursion limit * Deny to handle any blessed references (object instances) The following version of the RPC::XML::struct constructor checks for cyclic references in the data passed. my %cyclic; my %seen_cyclic; sub RPC::XML::struct::new { my $class = shift; my %args; if ( UNIVERSAL::isa($_[0], 'HASH') ) { # this is slooowww.... # find_weakened_cycle should only be called at the first level of # recursion. for that, RPC::XML::smart_encode would need to pass # an additional flag to RPC::XML::struct::new.... Devel::Cycle::find_weakened_cycle($_[0], \&callback ); %args = %{$_[0]}; } else { # struct::new should only get hashes from RPC::XML::smart_encode(), so... %args = @_; } # First ensure that each argument passed in is itself one of the data-type # class instances. for (keys %args) { if ( UNIVERSAL::isa($args{$_}, 'CODE') ) { # Remove CODE refs as we won't be able to stringify them delete $args{$_}; } # Check if we are dealing with a cyclic reference and if yes, # make sure it will only be handled once elsif ( exists $cyclic{$args{$_}} and not exists $seen_cyclic{$args{$_}} ) { $seen_cyclic{$args{$_}} = 1; $args{$_} = RPC::XML::smart_encode($args{$_}) unless (UNIVERSAL::isa($args{$_}, 'RPC::XML::datatype')); } elsif ( not exists $seen_cyclic{$args{$_}} ) { $args{$_} = RPC::XML::smart_encode($args{$_}) unless (UNIVERSAL::isa($args{$_}, 'RPC::XML::datatype')); } else { delete $args{$_}; } } bless \%args, $class; } sub callback { my $data = shift; foreach my $item ( @$data ) { $cyclic{$item->[2]} = 1 unless exists $cyclic{$item->[2]}; } }
Fixed, will be in the next release. -- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Randy J. Ray Silicon Valley Scale Modelers: http://www.svsm.org rjray@blackperl.com randy.j.ray@gmail.com
-- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Randy J. Ray Silicon Valley Scale Modelers: http://www.svsm.org rjray@blackperl.com randy.j.ray@gmail.com
-- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Randy J. Ray Silicon Valley Scale Modelers: http://www.svsm.org rjray@blackperl.com randy.j.ray@gmail.com