Perl provides several functions for list manipulation. For instance, the map()
function takes an expression or block, applies it to each element in a list, and returns the list of mapped elements. If it is given a block, the block is executed with $_
assigned to each element of the list in turn. The perlfunc manpage adds:
Note that $_ is an alias to the list value, so it can be used to modify the elements of the LIST. While this is useful and supported, it can cause bizarre results if the elements of LIST are not variables. Using a regular "foreach" loop for this purpose would be clearer in most cases.
Although it is supported, using map()
to modify a list in place can lead to surprises in maintainability and is thus forbidden.
Many other list functions provide similar functionality, using a block on various list elements. The grep()
function is one such example, as are the first()
and reduce()
functions in List::Util
and all of the functions in List::MoreUtils
.
Finally, the sort()
function also provides aliases to its comparison blocks, so a comparison block for sort()
must not modify its variables.
Noncompliant Code Example (grep()
)
This noncompliant code example reads the /etc/passwd
file and lists all users who use /bin/sh
as their login shell.
open( PASSWD, "<", "/etc/passwd"); @users = <PASSWD>; @shell_users = grep +(s|/bin/sh||), @users; foreach $user (@shell_users) { print "Shell User: $user"; }
However, because the grep()
block removes /bin/sh
from any input line that contains it, it modifies the @users
list so that no user has /bin/sh
!
Compliant Solution grep()
This compliant solution does the same thing but does not modify the @users
array.
open( PASSWD, "<", "/etc/passwd"); @users = <PASSWD>; @shell_users = grep +(m|/bin/sh|), @users; foreach $user (@shell_users) { $user ~= s|/bin/sh||; print "Shell User: $user"; }
If any error occurs, the program calls the croak()
function, passing it a string that includes both the source file being opened and the $!
variable, which contains a system error string based on the value of errno
. errno
is set to a useful value when the open(2)
or close(2)
functions fail.
Risk Assessment
Failure to handle error codes or other values returned by functions can lead to incorrect program flow and violations of data integrity.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
EXP34-PL |
medium |
likely |
low |
P6 |
L2 |
Automated Detection
Tool |
Diagnostic |
---|---|
Perl::Critic |
ControlStructures::ProhibitMutatingListFunctions |
Bibliography
[Conway 05] pg. 114 "List Processing Side Effects"
[Wall 2011] perlfunc
[CPAN] Bar, Graham. List::Utils
[CPAN] Kennedy, Adam
List::MoreUtils
EXP11-C. Do not apply operators expecting one type to data of an incompatible type 03. Expressions (EXP) EXP13-C. Treat relational and equality operators as if they were nonassociative