From 41aa1b345f3069cef72edacd7b40ce56e9169191 Mon Sep 17 00:00:00 2001 From: Ed Avis Date: Thu, 18 Mar 2021 11:15:12 +0000 Subject: [PATCH 1/2] Sort hash keys before iterating over them, for deterministic behaviour. --- Changes | 4 ++++ lib/CGI.pm | 26 +++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Changes b/Changes index 1477a1a..970b6d2 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,7 @@ +(upcoming) 2021-03-18 + [ FIX ] + - sort hash keys for deterministic behaviour (GH #245) + 4.51 2020-10-01 [ DOCUMENTATION ] diff --git a/lib/CGI.pm b/lib/CGI.pm index b4bd32d..4aa6a25 100644 --- a/lib/CGI.pm +++ b/lib/CGI.pm @@ -286,7 +286,7 @@ sub import { # To allow overriding, search through the packages # Till we find one in which the correct subroutine is defined. my @packages = ($self,@{"$self\:\:ISA"}); - for $sym (keys %EXPORT) { + for $sym (sort keys %EXPORT) { my $pck; my $def = $DefaultClass; for $pck (@packages) { @@ -609,7 +609,7 @@ sub init { last METHOD; } if (ref($initializer) && ref($initializer) eq 'HASH') { - for (keys %$initializer) { + for (sort keys %$initializer) { $self->param('-name'=>$_,'-value'=>$initializer->{$_}); } last METHOD; @@ -1155,7 +1155,7 @@ sub import_names { die "Can't import names into \"main\"\n" if \%{"${namespace}::"} == \%::; if ($delete || $MOD_PERL || exists $ENV{'FCGI_ROLE'}) { # can anyone find an easier way to do this? - for (keys %{"${namespace}::"}) { + for (sort keys %{"${namespace}::"}) { local *symbol = "${namespace}::${_}"; undef $symbol; undef @symbol; @@ -1428,7 +1428,7 @@ sub save { if length($escaped_param) or length($value); } } - for (keys %{$self->{'.fieldnames'}}) { + for (sort keys %{$self->{'.fieldnames'}}) { print $filehandle ".cgifields=",escape("$_"),"\n"; } print $filehandle "=\n"; # end of record @@ -2456,7 +2456,7 @@ sub popup_menu { if (/{'.fieldnames'}}) { + for (sort keys %{$self->{'.fieldnames'}}) { push(@pairs,".cgifields=".escape("$_")); } return join($USE_PARAM_SEMICOLONS ? ';' : '&',@pairs); @@ -2991,7 +2991,7 @@ sub Accept { return $prefs{$search} if $prefs{$search}; # Didn't get it, so try pattern matching. - for (keys %prefs) { + for (sort keys %prefs) { next unless /\*/; # not a pattern match ($pat = $_) =~ s/([^\w*])/\\$1/g; # escape meta characters $pat =~ s/\*/.*/g; # turn it into a pattern @@ -3144,7 +3144,7 @@ sub http { } return $ENV{"HTTP_$parameter"}; } - return grep { /^HTTP(?:_|$)/ } keys %ENV; + return grep { /^HTTP(?:_|$)/ } sort keys %ENV; } #### Method: https @@ -3162,7 +3162,7 @@ sub https { return $ENV{"HTTPS_$parameter"}; } return wantarray - ? grep { /^HTTPS(?:_|$)/ } keys %ENV + ? grep { /^HTTPS(?:_|$)/ } sort keys %ENV : $ENV{'HTTPS'}; } @@ -3293,7 +3293,7 @@ sub register_parameter { sub get_fields { my($self) = @_; return $self->CGI::hidden('-name'=>'.cgifields', - '-values'=>[keys %{$self->{'.parametersToAdd'}}], + '-values'=>[sort keys %{$self->{'.parametersToAdd'}}], '-override'=>1); } @@ -3415,7 +3415,7 @@ sub read_multipart { # together with the body for later parsing with an external # MIME parser module if ( $multipart ) { - for ( keys %header ) { + for ( sort keys %header ) { print $filehandle "$_: $header{$_}${CRLF}"; } print $filehandle "${CRLF}"; @@ -3633,7 +3633,7 @@ sub _set_attributes { my($element, $attributes) = @_; return '' unless defined($attributes->{$element}); $attribs = ' '; - for my $attrib (keys %{$attributes->{$element}}) { + for my $attrib (sort keys %{$attributes->{$element}}) { (my $clean_attrib = $attrib) =~ s/^-//; $attribs .= "@{[lc($clean_attrib)]}=\"$attributes->{$element}{$attrib}\" "; } From 99e2f13611484973a9c8281fccaba58df5f07078 Mon Sep 17 00:00:00 2001 From: Ed Avis Date: Thu, 18 Mar 2021 12:04:45 +0000 Subject: [PATCH 2/2] _set_values_and_labels: here too sort keys for deterministic behaviour. --- lib/CGI.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CGI.pm b/lib/CGI.pm index 4aa6a25..d4c91e0 100644 --- a/lib/CGI.pm +++ b/lib/CGI.pm @@ -3624,7 +3624,7 @@ sub _set_values_and_labels { $$l = $v if ref($v) eq 'HASH' && !ref($$l); return $self->param($n) if !defined($v); return $v if !ref($v); - return ref($v) eq 'HASH' ? keys %$v : @$v; + return ref($v) eq 'HASH' ? sort keys %$v : @$v; } # internal routine, don't use