Search code examples
perl

Type of arg 1 to keys must be hash error shows on Perl 5.10 but not Perl 5.16


I keep getting the following error:

Type of arg 1 to keys must be hash (not hash element)

at this line:

my $command = join(" ", @{$jparams{args}})
  . " -cp " . $jparams{cp}
  . " "     . $jparams{class}
  . " "     . join(" ",
     map {
       ${_} . "=" . qq|"$jparams{params}{$_}"|
     } keys $jparams{params}
  );

The error shows on Perl 5.10 but not Perl 5.16. How do I get it to work across both versions?


Solution

  • keys $jparams{params}
    

    should be

    keys %{ $jparams{params} }
    

    Your code suffers from code injection bugs.

    If the command is passed to system (or exec), use its multi-argument form.

    my @command = (
       @{ $jparams{ args } },
       -cp => $jparams{ cp },
       $jparams{ class },
       map { "$_=$jparams{ params }{ $_ }" }
          keys %{ $jparams{ params } },
    );
    
    system { $command[0] } @command;
    

    Not only will this solve the problem, it will avoid needlessly spawning a shell.

    But if you do need a shell command for some reason, your code injectiong bugs can be solved using String::ShellQuote's shell_quote.

    my @command = (
       @{ $jparams{ args } },
       -cp => $jparams{ cp },
       $jparams{ class },
       map { "$_=$jparams{ params }{ $_ }" }
          keys %{ $jparams{ params } },
    );
    
    my $command = shell_quote( @command );