Control: tag -1 patch On Sun, Dec 25, 2016 at 12:24:45AM +0100, Johannes Schauer wrote: > Package: libconfig-inifiles-perl > Version: 2.94-1 > Severity: normal
> use Config::IniFiles; > tie (my %ini, 'Config::IniFiles', -file=>"test.ini"); > foreach my $s (keys %ini) { > while (my ($k,$v) = each %{$ini{$s}}) { > print("$s $k $v\n"); > } > } > The result will be an infinite loop printing "foo bar baz". Thanks for the report. What is happening is that every time $ini{$s} is evaluated, Config::IniFiles::FETCH() creates a new Config::IniFiles::_section tied hash that has its own each() iterator. A workaround is to do something like foreach my $s (@k) { my $i = $ini{$s}; while (my ($k,$v) = each %$i) { print("$s $k $v\n"); } } but I'm attaching a patch that seems to fix this without breaking any existing tests. -- Niko Tyni nt...@debian.org
>From b9acffc56b85c71cde4b13751256bb37a64d9c2a Mon Sep 17 00:00:00 2001 From: Niko Tyni <nt...@debian.org> Date: Sun, 25 Dec 2016 21:38:51 +0200 Subject: [PATCH] Reuse Config::IniFiles::_section hashes in Config::IniFiles::FETCH As reported by Johannes Schauer, code like foreach my $s (keys %ini) { while (my ($k,$v) = each %{$ini{$s}}) { print("$s $k $v\n"); } } goes to an infinite loop. This is because every time $ini{$s} is evaluated, Config::IniFiles::FETCH() creates a new Config::IniFiles::_section tied hash that has its own each() iterator. Store and reuse the section hashes instead. Bug-Debian: https://bugs.debian.org/849298 --- lib/Config/IniFiles.pm | 6 +++++- t/35section-iterators.t | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 t/35section-iterators.t diff --git a/lib/Config/IniFiles.pm b/lib/Config/IniFiles.pm index 85296e8..817dece 100644 --- a/lib/Config/IniFiles.pm +++ b/lib/Config/IniFiles.pm @@ -1841,12 +1841,16 @@ sub FETCH { my $self = shift; my( $key ) = @_; + $self->{_section_cache} ||= {}; + $self->_caseify(\$key); return if (! $self->{v}{$key}); + return $self->{_section_cache}->{$key} if exists $self->{_section_cache}->{$key}; + my %retval; tie %retval, 'Config::IniFiles::_section', $self, $key; - return \%retval; + return $self->{_section_cache}->{$key} = \%retval; } # end FETCH diff --git a/t/35section-iterators.t b/t/35section-iterators.t new file mode 100644 index 0000000..54adf7f --- /dev/null +++ b/t/35section-iterators.t @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +# See: https://bugs.debian.org/849298 + +use strict; +use warnings; + +use Test::More tests => 2; + +use Config::IniFiles; + +my $ini_contents = <<'EOF'; +[foo] +bar=baz +rab=zab +EOF + +tie (my %ini, 'Config::IniFiles', -file=>\$ini_contents); + +my ($k1,$v1) = each %{$ini{foo}}; +my ($k2,$v2) = each %{$ini{foo}}; + +isnt($k1, $k2, "got different keys with successive each() calls"); +isnt($v1, $v2, "got different values with successive each() calls"); -- 2.11.0