Subject: | Many single quoted strings and -InterPolateVars causes value corruption |
When there are many single-quoted strings in a config line, a problem
sometimes corrupts the text, with one or more single-quoted strings
replaced with text like "QUOTE279QUOTE".
A config line like
sheep_tale 'Mary' 'had' 'a' 'little' 'lamb'
can sometimes be seen by a program as
"'Mary' 'had' 'a' QUOTE999QUOTE 'lamb'"
Depending on the number of lines in a config file which have multiple
single-quoted strings, this may happen only infrequently. (If there is
only one single-quoted string per line the problem will not happen.)
Routine Config::General::Interpolated::_interpolate() uses a method of
temporarily replacing single-quoted strings in order to avoid 'seeing'
these when looking for ${var} during interpolation. At the end of the
routine the replaced text segments are restored from a hash.
However the method for generating the hash keys is able to accidentally
*repeat* a key more than once, and then loses track of one or more
single-quoted strings. These then don't get replaced and the weird
placeholder texts remain in the value.
The fix is to use a simple counter within the routine to generate keys
as needed.
That patch file is attached, along with a test file that demonstrates
the problem before patching, and that the problem is fixed after patch
applied.
Please note that the patch also includes the rest of the suggested patch
in a previous bug report. Old bug
46184 When -InterPolateEnv is enabled, -StrictVars is ignored
suggested a patch that moved some code out of _interpolate() into
_interpolate_hash(). Deleting the moved code from _interpolate() was
missed. That was noticed while researching the present bug.
This bug report is also related to the first problem mentioned in bug
51494, which had an alternate solution using split().
Subject: | 90_RTxxxxx_interpolate_single_quotes.t |
# This test relates to the first part of the following bug report
# CPAN RT bug report #51494
# https://rt.cpan.org/Public/Bug/Display.html?id=51494
# which was separately discovered and noted
my $debug_here = 0;
use Test::More tests => 2;
#use Test::More qw(no_plan);
use Data::Dumper;
BEGIN { use_ok "Config::General"};
#------------------------------------------------------------------
# Test handling of values containing *many* single-quoted strings
# when -InterPolateVars option is set
# - - - - - - - - - - - - - -
# Create a test string value containing many single-quoted strings
my $duplication_count = 2000;
# $duplication_count = 100;
# This produces a lot of different quoted strings with explicit ordering.
# By using this input it becomes even more obvious what goes wrong.
my $text_for_test;
foreach my $counter ( reverse 1 .. $duplication_count ) {
$text_for_test .= " 'luck${counter}'";
}
# remove the extra leading space from test value, as C::G will strip
# leading/trailing spaces on read, causing later mismatch on test
$text_for_test =~ s{\A }{};
# Create the config source line: key plus value
my $config_source_text = 'test_single_many ' . $text_for_test;
diag qq{config_source_text: '$config_source_text'} if $debug_here > 1;
# - - - - - - - - - - - - - -
$cfgo = Config::General->new(
-String => $config_source_text,
-InterPolateVars => 1
);
%hash = $cfgo->getall;
diag( Data::Dumper->Dump([ \%hash ], [qw{ *hash }]) ) if $debug_here > 1;
$text_from_test = $hash{test_single_many};
is( $text_from_test, $text_for_test,
"value with single-quote strings is as expected" );
if ( $debug_here ) {
my @oops = $text_from_test =~ m{QUOTE\d+QUOTE}g;
diag "Found @{[ scalar @oops ]} accidents";
}
__END__
not ok 2 - value with single-quote strings is same
# Failed test 'value with single-quote strings is same'
# at t\80_interpolate.t line 56.
# got: ''luck' 'luck' 'luck' QUOTE279QUOTE 'luck''
# expected: ''luck' 'luck' 'luck' 'luck' 'luck''
# Found 1 accidents
# vim:ft=perl:ts=4:sw=4:et:is:hls:ss=10:
Subject: | Interpolated.pm.RTxxxxx.patch |
--- Interpolated.pm.original 2009-07-19 15:04:51.000000000 -0500
+++ Interpolated.pm 2010-02-12 20:57:26.343373600 -0600
@@ -65,6 +65,7 @@
# called directly by Config::General::_parse_value()
#
my ($this, $config, $key, $value) = @_;
+ my $quote_counter = 100;
# some dirty trick to circumvent single quoted vars to be interpolated
# we remove all quotes and replace them with unique random literals,
@@ -72,7 +73,7 @@
# fixes bug rt#35766
my %quotes;
$value =~ s/(\'[^\']+?\')/
- my $key = "QUOTE" . int(rand(1000)) . "QUOTE";
+ my $key = "QUOTE" . ($quote_counter++) . "QUOTE";
$quotes{ $key } = $1;
$key;
/gex;
@@ -85,23 +86,12 @@
if (exists $config->{__stack}->{$var_lc}) {
$con . $config->{__stack}->{$var_lc};
}
- elsif ($this->{InterPolateEnv}) {
- # may lead to vulnerabilities, by default flag turned off
- if (defined($ENV{$var})) {
- $con . $ENV{$var};
- }
- else {
- $con;
- }
- }
- else {
- if ($this->{StrictVars}) {
+ elsif ($this->{StrictVars}) {
croak "Use of uninitialized variable (\$$var) while loading config entry: $key = $value\n";
}
- else {
- # be cool
- $con;
- }
+ else {
+ # be cool
+ $con;
}
}egx;